X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=blobdiff_plain;f=trp%2Ftrps.c;fp=trp%2Ftrps.c;h=b4051e1470c38044ee6b485a9cf2dd62ba63fb9d;hp=ebc365da906662176f2c5421d48f16ac34ea5d19;hb=6f65c9cce86719147d0b4dcc9823b25443c2d185;hpb=eaa1a8ceed54fbfadc2638cf383aaa12ab446a57 diff --git a/trp/trps.c b/trp/trps.c index ebc365d..b4051e1 100644 --- a/trp/trps.c +++ b/trp/trps.c @@ -39,18 +39,22 @@ #include #include #include +#include // for nfds_t #include #include #include #include #include +#include #include -#include +#include +#include #include #include #include #include +#include static int trps_destructor(void *object) { @@ -65,7 +69,7 @@ TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx) TRPS_INSTANCE *trps=talloc(mem_ctx, TRPS_INSTANCE); if (trps!=NULL) { trps->hostname=NULL; - trps->port=0; + trps->trps_port=0; trps->cookie=NULL; trps->conn=NULL; trps->trpc=NULL; @@ -192,7 +196,7 @@ TR_NAME *trps_dup_label(TRPS_INSTANCE *trps) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_NAME *label=NULL; - char *s=talloc_asprintf(tmp_ctx, "%s:%u", trps->hostname, trps->port); + char *s=talloc_asprintf(tmp_ctx, "%s:%u", trps->hostname, trps->trps_port); if (s==NULL) goto cleanup; label=tr_new_name(s); @@ -261,12 +265,15 @@ TRP_RC trps_send_msg(TRPS_INSTANCE *trps, TRP_PEER *peer, const char *msg) /* get the connection for this peer */ trpc=trps_find_trpc(trps, peer); - /* instead, let's let that happen and then clear the queue when an attempt to - * connect fails */ + /* The peer connection (trpc) usually exists even if the connection is down. + * We will queue messages even if the connection is down. To prevent this from + * endlessly increasing the size of the queue, the trpc handler needs to clear + * its queue periodically, even if it is unable to send the messages + */ if (trpc==NULL) { tr_warning("trps_send_msg: skipping message queued for missing TRP client entry."); } else { - mq_msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPC_SEND, TR_MQ_PRIO_NORMAL); + mq_msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPC_SEND); msg_dup=talloc_strdup(mq_msg, msg); /* get local copy in mq_msg context */ tr_mq_msg_set_payload(mq_msg, msg_dup, NULL); /* no need for a free() func */ trpc_mq_add(trpc, mq_msg); @@ -276,82 +283,6 @@ TRP_RC trps_send_msg(TRPS_INSTANCE *trps, TRP_PEER *peer, const char *msg) return rc; } -/* 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; - int optval=0; - 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; - 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; - } - getaddrinfo(NULL, port_str, &hints, &ai_head); - talloc_free(port_str); - - 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) { - /* 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 (n_opened==0) { - tr_debug("trps_listen: no addresses available for listening."); - return -1; - } - - tr_debug("trps_listen: TRP Server listening on port %d on %d socket%s", - port, - n_opened, - (n_opened==1)?"":"s"); - - return n_opened; -} - /* get the currently selected route if available */ TRP_ROUTE *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer) { @@ -410,7 +341,7 @@ static TRP_RC trps_read_message(TRPS_INSTANCE *trps, TRP_CONNECTION *conn, TR_MS tr_debug("trps_read_message: message received, %u bytes.", (unsigned) buflen); tr_debug("trps_read_message: %.*s", buflen, buf); - *msg=tr_msg_decode(buf, buflen); + *msg= tr_msg_decode(NULL, buf, buflen); free(buf); if (*msg==NULL) return TRP_NOPARSE; @@ -431,7 +362,6 @@ static TRP_RC trps_read_message(TRPS_INSTANCE *trps, TRP_CONNECTION *conn, TR_MS switch (tr_msg_get_msg_type(*msg)) { case TRP_UPDATE: trp_upd_set_peer(tr_msg_get_trp_upd(*msg), tr_dup_name(conn_peer)); - trp_upd_set_next_hop(tr_msg_get_trp_upd(*msg), trp_peer_get_server(peer), 0); /* TODO: 0 should be the configured TID port */ /* update provenance if necessary */ trp_upd_add_to_provenance(tr_msg_get_trp_upd(*msg), trp_peer_get_label(peer)); break; @@ -454,17 +384,18 @@ int trps_get_listener(TRPS_INSTANCE *trps, TRPS_MSG_FUNC msg_handler, TRP_AUTH_FUNC auth_handler, const char *hostname, - unsigned int port, + int port, void *cookie, int *fd_out, size_t max_fd) { - size_t n_fd=0; - size_t ii=0; + nfds_t n_fd=0; + nfds_t ii=0; + + n_fd = tr_sock_listen_all(port, fd_out, max_fd); - n_fd=trps_listen(trps, port, fd_out, max_fd); - if (n_fd==0) - tr_err("trps_get_listener: Error opening port %d."); + if (n_fd == 0) + tr_err("trps_get_listener: Error opening port %d.", port); else { /* opening port succeeded */ tr_info("trps_get_listener: Opened port %d.", port); @@ -477,33 +408,33 @@ int trps_get_listener(TRPS_INSTANCE *trps, close(fd_out[ii]); fd_out[ii]=-1; } - n_fd=0; + n_fd = 0; break; } } } - if (n_fd>0) { + if (n_fd > 0) { /* store the caller's request handler & cookie */ trps->msg_handler = msg_handler; trps->auth_handler = auth_handler; trps->hostname = talloc_strdup(trps, hostname); - trps->port = port; + trps->trps_port = port; trps->cookie = cookie; } - return n_fd; + return (int) n_fd; } TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn) { /* try to establish a GSS context */ if (0!=trp_connection_auth(conn, trps->auth_handler, trps->cookie)) { - tr_notice("trps_authorize_connection: failed to authorize connection"); + tr_debug("trps_authorize_connection: failed to authorize connection"); trp_connection_close(conn); return TRP_ERROR; } - tr_notice("trps_authorize_connection: authorized connection"); + tr_debug("trps_authorize_connection: authorized connection"); return TRP_SUCCESS; } @@ -570,12 +501,27 @@ static TRP_RC trps_validate_inforec(TRPS_INSTANCE *trps, TRP_INFOREC *rec) switch(trp_inforec_get_type(rec)) { case TRP_INFOREC_TYPE_ROUTE: if ((trp_inforec_get_trust_router(rec)==NULL) - || (trp_inforec_get_next_hop(rec)==NULL)) { + || (trp_inforec_get_next_hop(rec)==NULL)) { tr_debug("trps_validate_inforec: missing record info."); return TRP_ERROR; } - /* check for valid metric */ + /* check for valid ports */ + if ((trp_inforec_get_trust_router_port(rec) <= 0) + || (trp_inforec_get_trust_router_port(rec) > 65535)) { + tr_debug("trps_validate_inforec: invalid trust router port (%d)", + trp_inforec_get_trust_router_port(rec)); + return TRP_ERROR; + } + + if ((trp_inforec_get_next_hop_port(rec) <= 0) + || (trp_inforec_get_next_hop_port(rec) > 65535)) { + tr_debug("trps_validate_inforec: invalid next hop port (%d)", + trp_inforec_get_next_hop_port(rec)); + return TRP_ERROR; + } + + /* check for valid metric */ if (trp_metric_is_invalid(trp_inforec_get_metric(rec))) { tr_debug("trps_validate_inforec: invalid metric (%u).", trp_inforec_get_metric(rec)); return TRP_ERROR; @@ -661,6 +607,17 @@ static struct timespec *trps_compute_expiry(TRPS_INSTANCE *trps, unsigned int in return ts; } + +/* compare hostname/port of the trust router, return 0 if they match */ +static int trust_router_changed(TRP_ROUTE *route, TRP_INFOREC *rec) +{ + if (trp_route_get_trust_router_port(route) != trp_inforec_get_trust_router_port(rec)) + return 1; + + return tr_name_cmp(trp_route_get_trust_router(route), + trp_inforec_get_trust_router(rec)); +} + static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec) { TRP_ROUTE *entry=NULL; @@ -680,8 +637,9 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC trp_route_set_realm(entry, trp_upd_dup_realm(upd)); trp_route_set_peer(entry, trp_upd_dup_peer(upd)); trp_route_set_trust_router(entry, trp_inforec_dup_trust_router(rec)); + trp_route_set_trust_router_port(entry, trp_inforec_get_trust_router_port(rec)); trp_route_set_next_hop(entry, trp_inforec_dup_next_hop(rec)); - /* TODO: pass next hop port (now defaults to TID_PORT) --jlr */ + trp_route_set_next_hop_port(entry, trp_inforec_get_next_hop_port(rec)); if ((trp_route_get_comm(entry)==NULL) ||(trp_route_get_realm(entry)==NULL) ||(trp_route_get_peer(entry)==NULL) @@ -703,13 +661,13 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC trp_route_set_metric(entry, trp_inforec_get_metric(rec)); trp_route_set_interval(entry, trp_inforec_get_interval(rec)); - /* check whether the trust router has changed */ - if (0!=tr_name_cmp(trp_route_get_trust_router(entry), - trp_inforec_get_trust_router(rec))) { + /* check whether the trust router has changed (either name or port) */ + if (trust_router_changed(entry, rec)) { /* The name changed. Set this route as triggered. */ tr_debug("trps_accept_update: trust router for route changed."); trp_route_set_triggered(entry, 1); trp_route_set_trust_router(entry, trp_inforec_dup_trust_router(rec)); /* frees old name */ + trp_route_set_trust_router_port(entry, trp_inforec_get_trust_router_port(rec)); } if (!trps_route_retracted(trps, entry)) { tr_debug("trps_accept_update: route not retracted, setting expiry timer."); @@ -724,36 +682,50 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC static TRP_RC trps_handle_inforec_route(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec) { TRP_ROUTE *route=NULL; + TR_COMM *comm = NULL; unsigned int feas=0; /* determine feasibility */ feas=trps_check_feasibility(trps, trp_upd_get_realm(upd), trp_upd_get_comm(upd), rec); tr_debug("trps_handle_update: record feasibility=%d", feas); - /* do we have an existing route? */ - route=trps_get_route(trps, - trp_upd_get_comm(upd), - trp_upd_get_realm(upd), - trp_upd_get_peer(upd)); - if (route!=NULL) { - /* there was a route table entry already */ - tr_debug("trps_handle_updates: route entry already exists."); - if (feas) { - /* Update is feasible. Accept it. */ - trps_accept_update(trps, upd, rec); - } else { - /* Update is infeasible. Ignore it unless the trust router has changed. */ - if (0!=tr_name_cmp(trp_route_get_trust_router(route), - trp_inforec_get_trust_router(rec))) { - /* the trust router associated with the route has changed, treat update as a retraction */ - trps_retract_route(trps, route); + /* verify that the community is an APC */ + comm = tr_comm_table_find_comm(trps->ctable, trp_upd_get_comm(upd)); + if (comm == NULL) { + /* We don't know this community. Reject the route. */ + tr_debug("trps_handle_updates: community %.*s unknown, ignoring route for %.*s", + trp_upd_get_comm(upd)->len, trp_upd_get_comm(upd)->buf, + trp_upd_get_realm(upd)->len, trp_upd_get_realm(upd)->buf); + } else if (tr_comm_get_type(comm) != TR_COMM_APC) { + /* The community in a route request *must* be an APC. This was not - ignore it. */ + tr_debug("trps_handle_updates: community %.*s is not an APC, ignoring route for %.*s", + trp_upd_get_comm(upd)->len, trp_upd_get_comm(upd)->buf, + trp_upd_get_realm(upd)->len, trp_upd_get_realm(upd)->buf); + } else { + /* do we have an existing route? */ + route=trps_get_route(trps, + trp_upd_get_comm(upd), + trp_upd_get_realm(upd), + trp_upd_get_peer(upd)); + if (route!=NULL) { + /* there was a route table entry already */ + tr_debug("trps_handle_updates: route entry already exists."); + if (feas) { + /* Update is feasible. Accept it. */ + trps_accept_update(trps, upd, rec); + } else { + /* Update is infeasible. Ignore it unless the trust router has changed. */ + if (trust_router_changed(route, rec)) { + /* the trust router associated with the route has changed, treat update as a retraction */ + trps_retract_route(trps, route); + } } + } else { + /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */ + tr_debug("trps_handle_update: no route entry exists yet."); + if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec))) + trps_accept_update(trps, upd, rec); } - } else { - /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */ - tr_debug("trps_handle_update: no route entry exists yet."); - if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec))) - trps_accept_update(trps, upd, rec); } return TRP_SUCCESS; @@ -839,7 +811,7 @@ cleanup: return comm; } -static TR_RP_REALM *trps_create_new_rp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec) +static TR_RP_REALM *trps_create_new_rp_realm(TALLOC_CTX *mem_ctx, TR_NAME *comm, TR_NAME *realm_id, TRP_INFOREC *rec) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_RP_REALM *rp=tr_rp_realm_new(tmp_ctx); @@ -862,11 +834,15 @@ cleanup: return rp; } -static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec) +static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, + TR_NAME *comm_id, + TR_NAME *realm_id, + TRP_INFOREC *rec) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_IDP_REALM *idp=tr_idp_realm_new(tmp_ctx); - + TR_APC *realm_apcs = NULL; + if (idp==NULL) { tr_debug("trps_create_new_idp_realm: unable to allocate new realm."); goto cleanup; @@ -878,14 +854,52 @@ static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, TR_NAME *rea idp=NULL; goto cleanup; } - if (trp_inforec_get_apcs(rec)!=NULL) { - tr_idp_realm_set_apcs(idp, tr_apc_dup(tmp_ctx, trp_inforec_get_apcs(rec))); - if (tr_idp_realm_get_apcs(idp)==NULL) { - tr_debug("trps_create_new_idp_realm: unable to allocate APC list."); - idp=NULL; + + /* Set the APCs. If the community is a CoI, copy its APCs. If it is an APC, then + * that community itself is the APC for the realm. */ + if (trp_inforec_get_comm_type(rec) == TR_COMM_APC) { + /* the community is an APC for this realm */ + realm_apcs = tr_apc_new(tmp_ctx); + if (realm_apcs == NULL) { + tr_debug("trps_create_new_idp_realm: unable to allocate new APC list."); + idp = NULL; + goto cleanup; + } + + tr_apc_set_id(realm_apcs, tr_dup_name(comm_id)); + if (tr_apc_get_id(realm_apcs) == NULL) { + tr_debug("trps_create_new_idp_realm: unable to allocate new APC name."); + idp = NULL; + goto cleanup; + } + } else { + /* the community is not an APC for this realm */ + realm_apcs = trp_inforec_get_apcs(rec); + if (realm_apcs == NULL) { + tr_debug("trps_create_new_idp_realm: no APCs for realm %.*s/%.*s, cannot add.", + realm_id->len, realm_id->buf, + comm_id->len, comm_id->buf); + idp = NULL; + goto cleanup; + } + + /* we have APCs, make our own copy */ + realm_apcs = tr_apc_dup(tmp_ctx, realm_apcs); + if (realm_apcs == NULL) { + tr_debug("trps_create_new_idp_realm: unable to duplicate APC list."); + idp = NULL; goto cleanup; } } + + /* Whether the community is an APC or CoI, the APCs for the realm are in realm_apcs */ + tr_idp_realm_set_apcs(idp, realm_apcs); /* takes realm_apcs out of tmp_ctx on success */ + if (tr_idp_realm_get_apcs(idp) == NULL) { + tr_debug("trps_create_new_idp_realm: unable to set APC list for new realm."); + idp=NULL; + goto cleanup; + } + idp->origin=TR_REALM_DISCOVERED; talloc_steal(mem_ctx, idp); @@ -935,7 +949,11 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN tr_debug("trps_handle_inforec_comm: unable to create new community."); goto cleanup; } - tr_comm_table_add_comm(trps->ctable, comm); + if (tr_comm_table_add_comm(trps->ctable, comm) != 0) + { + tr_debug("trps_handle_inforec_comm: unable to add community to community table."); + goto cleanup; + } } /* TODO: see if other comm data match the new inforec and update or complain */ @@ -949,7 +967,7 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN if (rp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unknown RP realm %.*s in inforec, creating it.", realm_id->len, realm_id->buf); - rp_realm=trps_create_new_rp_realm(tmp_ctx, realm_id, rec); + rp_realm= trps_create_new_rp_realm(tmp_ctx, tr_comm_get_id(comm), realm_id, rec); if (rp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unable to create new RP realm."); /* we may leave an unused community in the table, but it will only last until @@ -970,7 +988,7 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN if (idp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unknown IDP realm %.*s in inforec, creating it.", realm_id->len, realm_id->buf); - idp_realm=trps_create_new_idp_realm(tmp_ctx, realm_id, rec); + idp_realm= trps_create_new_idp_realm(tmp_ctx, tr_comm_get_id(comm), realm_id, rec); if (idp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unable to create new IDP realm."); /* we may leave an unused community in the table, but it will only last until @@ -1123,12 +1141,13 @@ static TRP_RC trps_validate_request(TRPS_INSTANCE *trps, TRP_REQ *req) /* choose the best route to comm/realm, optionally excluding routes to a particular peer */ static TRP_ROUTE *trps_find_best_route(TRPS_INSTANCE *trps, - TR_NAME *comm, - TR_NAME *realm, - TR_NAME *exclude_peer) + TR_NAME *comm, + TR_NAME *realm, + TR_NAME *exclude_peer_label) { TRP_ROUTE **entry=NULL; TRP_ROUTE *best=NULL; + TRP_PEER *route_peer = NULL; size_t n_entry=0; unsigned int kk=0; unsigned int kk_min=0; @@ -1137,13 +1156,31 @@ static TRP_ROUTE *trps_find_best_route(TRPS_INSTANCE *trps, entry=trp_rtable_get_realm_entries(trps->rtable, comm, realm, &n_entry); for (kk=0; kkptable, + trp_route_get_peer(entry[kk])); + if (route_peer == NULL) { + tr_err("trps_find_best_route: unknown peer GSS name (%.*s) for route %d to %.*s/%.*s", + trp_route_get_peer(entry[kk])->len, trp_route_get_peer(entry[kk])->buf, + kk, + realm->len, realm->buf, + comm->len, comm->buf); + continue; /* unknown peer, skip the route */ + } + if (0 == tr_name_cmp(exclude_peer_label, trp_peer_get_label(route_peer))) { + /* we're excluding this peer - skip the route */ + continue; + } + } + } + /* if we get here, we're not excluding the route */ + kk_min = kk; + min_metric = trp_route_get_metric(entry[kk]); } } + if (trp_metric_is_finite(min_metric)) best=entry[kk_min]; @@ -1218,7 +1255,7 @@ TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps) return TRP_ERROR; } - entry=trp_rtable_get_entries(trps->rtable, &n_entry); /* must talloc_free *entry */ + entry= trp_rtable_get_entries(NULL, trps->rtable, &n_entry); /* must talloc_free *entry */ /* loop over the entries */ for (ii=0; iitv_sec), &tm)==NULL) - return NULL; - - s=malloc(40); /* long enough to contain strftime result */ - if (s==NULL) - return NULL; - - if (strftime(s, 40, "%F %T", &tm)==0) { - free(s); - return NULL; - } - return s; -} - - /* Sweep for expired communities/realms/memberships. */ TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); struct timespec sweep_time={0,0}; + struct timespec tmp = {0}; TR_COMM_MEMB *memb=NULL; TR_COMM_ITER *iter=NULL; TRP_RC rc=TRP_ERROR; @@ -1302,7 +1320,7 @@ TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps) tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf, tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf, tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf, - timespec_to_str(tr_comm_memb_get_expiry(memb))); + timespec_to_str(tr_comm_memb_get_expiry_realtime(memb, &tmp))); tr_comm_table_remove_memb(trps->ctable, memb); tr_comm_memb_free(memb); } else { @@ -1310,8 +1328,8 @@ TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps) tr_comm_memb_expire(memb); trps_compute_expiry(trps, tr_comm_memb_get_interval(memb), tr_comm_memb_get_expiry(memb)); tr_debug("trps_sweep_ctable: community membership expired at %s, resetting expiry to %s (%.*s in %.*s, origin %.*s).", - timespec_to_str(&sweep_time), - timespec_to_str(tr_comm_memb_get_expiry(memb)), + timespec_to_str(tr_clock_convert(TRP_CLOCK, &sweep_time, CLOCK_REALTIME, &tmp)), + timespec_to_str(tr_comm_memb_get_expiry_realtime(memb, &tmp)), tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf, tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf, tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf); @@ -1356,13 +1374,23 @@ static TRP_INFOREC *trps_route_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *tr trp_route_get_peer(route))); } - /* Note that we leave the next hop empty since the recipient fills that in. - * This is where we add the link cost (currently always 1) to the next peer. */ - if ((trp_inforec_set_trust_router(rec, trp_route_dup_trust_router(route)) != TRP_SUCCESS) - ||(trp_inforec_set_metric(rec, - trps_metric_add(trp_route_get_metric(route), - linkcost)) != TRP_SUCCESS) - ||(trp_inforec_set_interval(rec, trps_get_update_interval(trps)) != TRP_SUCCESS)) { + /* + * This is where we add the link cost (currently always 1) to the next peer. + * + * Here, set next_hop to our TID address/port rather than passing along our own + * next_hop. That is the one *we* use to forward requests. We are advertising + * ourselves as a hop for our peers. + */ + if ((TRP_SUCCESS != trp_inforec_set_trust_router(rec, + trp_route_dup_trust_router(route), + trp_route_get_trust_router_port(route))) + ||(TRP_SUCCESS != trp_inforec_set_next_hop(rec, + tr_new_name(trps->hostname), + trps->tids_port)) + ||(TRP_SUCCESS != trp_inforec_set_metric(rec, + trps_metric_add(trp_route_get_metric(route), + linkcost))) + ||(TRP_SUCCESS != trp_inforec_set_interval(rec, trps_get_update_interval(trps)))) { tr_err("trps_route_to_inforec: error creating route update."); talloc_free(rec); rec=NULL; @@ -1412,26 +1440,67 @@ cleanup: } /* select the correct route to comm/realm to be announced to peer */ -static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer_gssname) +static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer_label) { - TRP_ROUTE *route; + TRP_ROUTE *route = NULL; + TRP_PEER *route_peer = NULL; + TR_NAME *route_peer_label = NULL; /* Take the currently selected route unless it is through the peer we're sending the update to. - * I.e., enforce the split horizon rule. */ + * I.e., enforce the split horizon rule. Start by looking up the currently selected route. */ route=trp_rtable_get_selected_entry(trps->rtable, comm, realm); if (route==NULL) { /* No selected route, this should only happen if the only route has been retracted, * in which case we do not want to advertise it. */ return NULL; } - tr_debug("trps_select_realm_update: %s vs %s", peer_gssname->buf, - trp_route_get_peer(route)->buf); - if (0==tr_name_cmp(peer_gssname, trp_route_get_peer(route))) { - tr_debug("trps_select_realm_update: matched, finding alternate route"); - /* the selected entry goes through the peer we're reporting to, choose an alternate */ - route=trps_find_best_route(trps, comm, realm, peer_gssname); - if ((route==NULL) || (!trp_metric_is_finite(trp_route_get_metric(route)))) - return NULL; /* don't advertise a nonexistent or retracted route */ + + /* Check whether it's local. */ + if (trp_route_is_local(route)) { + /* It is always ok to announce a local route */ + tr_debug("trps_select_realm_update: selected route for %.*s/%.*s is local", + realm->len, realm->buf, + comm->len, comm->buf); + } else { + /* It's not local. Get the route's peer and check whether it's the same place we + * got the selected route from. Peer should always correspond to an entry in our + * peer table. */ + tr_debug("trps_select_realm_update: selected route for %.*s/%.*s is not local", + realm->len, realm->buf, + comm->len, comm->buf); + route_peer = trp_ptable_find_gss_name(trps->ptable, trp_route_get_peer(route)); + if (route_peer == NULL) { + tr_err("trps_select_realm_update: unknown peer GSS name (%.*s) for selected route for %.*s/%.*s", + trp_route_get_peer(route)->len, trp_route_get_peer(route)->buf, + realm->len, realm->buf, + comm->len, comm->buf); + return NULL; + } + route_peer_label = trp_peer_get_label(route_peer); + if (route_peer_label == NULL) { + tr_err("trps_select_realm_update: error retrieving peer label for selected route for %.*s/%.*s", + realm->len, realm->buf, + comm->len, comm->buf); + return NULL; + } + + /* see if these match */ + tr_debug("trps_select_realm_update: %.*s vs %.*s", + peer_label->len, peer_label->buf, + route_peer_label->len, route_peer_label->buf); + + if (0==tr_name_cmp(peer_label, route_peer_label)) { + /* the selected entry goes through the peer we're reporting to, choose an alternate */ + tr_debug("trps_select_realm_update: matched, finding alternate route"); + route=trps_find_best_route(trps, comm, realm, peer_label); + if ((route==NULL) || (!trp_metric_is_finite(trp_route_get_metric(route)))) { + tr_debug("trps_select_realm_update: no route to %.*s/%.*s suitable to advertise to %.*s", + realm->len, realm->buf, + comm->len, comm->buf, + peer_label->len, peer_label->buf); + return NULL; /* don't advertise a nonexistent or retracted route */ + } + } } return route; } @@ -1440,7 +1509,7 @@ static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, T static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, GPtrArray *updates, TRPS_INSTANCE *trps, - TR_NAME *peer_gssname, + TR_NAME *peer_label, int triggered) { size_t n_comm=0; @@ -1457,7 +1526,7 @@ static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, for (ii=0; iirtable, comm[ii], &n_realm); for (jj=0; jjlen, tr_realm_get_id(realm)->buf); - upd=trps_comm_update(mem_ctx, trps, peer_gssname, comm, realm); + upd=trps_comm_update(mem_ctx, trps, peer_label, comm, realm); if (upd!=NULL) g_ptr_array_add(updates, upd); } @@ -1821,7 +1894,7 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, upd = (TRP_UPD *) g_ptr_array_index(updates, ii); /* now encode the update message */ tr_msg_set_trp_upd(&msg, upd); - encoded = tr_msg_encode(&msg); + encoded = tr_msg_encode(NULL, &msg); if (encoded == NULL) { tr_err("trps_update_one_peer: error encoding update."); rc = TRP_ERROR; @@ -2006,7 +2079,7 @@ TRP_RC trps_wildcard_route_req(TRPS_INSTANCE *trps, TR_NAME *peer_servicename) } tr_msg_set_trp_req(&msg, req); - encoded=tr_msg_encode(&msg); + encoded= tr_msg_encode(NULL, &msg); if (encoded==NULL) { tr_err("trps_wildcard_route_req: error encoding wildcard TRP request."); rc=TRP_ERROR;