Annotation of embedaddon/bird2/proto/rpki/rpki.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
! 3: *
! 4: * (c) 2015 CZ.NIC
! 5: * (c) 2015 Pavel Tvrdik <pawel.tvrdik@gmail.com>
! 6: *
! 7: * Using RTRlib: http://rpki.realmv6.org/
! 8: *
! 9: * Can be freely distributed and used under the terms of the GNU GPL.
! 10: */
! 11:
! 12: /**
! 13: * DOC: RPKI To Router (RPKI-RTR)
! 14: *
! 15: * The RPKI-RTR protocol is implemented in several files: |rpki.c| containing
! 16: * the routes handling, protocol logic, timer events, cache connection,
! 17: * reconfiguration, configuration and protocol glue with BIRD core, |packets.c|
! 18: * containing the RPKI packets handling and finally all transports files:
! 19: * |transport.c|, |tcp_transport.c| and |ssh_transport.c|.
! 20: *
! 21: * The |transport.c| is a middle layer and interface for each specific
! 22: * transport. Transport is a way how to wrap a communication with a cache
! 23: * server. There is supported an unprotected TCP transport and an encrypted
! 24: * SSHv2 transport. The SSH transport requires LibSSH library. LibSSH is
! 25: * loading dynamically using |dlopen()| function. SSH support is integrated in
! 26: * |sysdep/unix/io.c|. Each transport must implement an initialization
! 27: * function, an open function and a socket identification function. That's all.
! 28: *
! 29: * This implementation is based on the RTRlib (http://rpki.realmv6.org/). The
! 30: * BIRD takes over files |packets.c|, |rtr.c| (inside |rpki.c|), |transport.c|,
! 31: * |tcp_transport.c| and |ssh_transport.c| from RTRlib.
! 32: *
! 33: * A RPKI-RTR connection is described by a structure &rpki_cache. The main
! 34: * logic is located in |rpki_cache_change_state()| function. There is a state
! 35: * machine. The standard starting state flow looks like |Down| ~> |Connecting|
! 36: * ~> |Sync-Start| ~> |Sync-Running| ~> |Established| and then the last three
! 37: * states are periodically repeated.
! 38: *
! 39: * |Connecting| state establishes the transport connection. The state from a
! 40: * call |rpki_cache_change_state(CONNECTING)| to a call |rpki_connected_hook()|
! 41: *
! 42: * |Sync-Start| state starts with sending |Reset Query| or |Serial Query| and
! 43: * then waits for |Cache Response|. The state from |rpki_connected_hook()| to
! 44: * |rpki_handle_cache_response_pdu()|
! 45: *
! 46: * During |Sync-Running| BIRD receives data with IPv4/IPv6 Prefixes from cache
! 47: * server. The state starts from |rpki_handle_cache_response_pdu()| and ends
! 48: * in |rpki_handle_end_of_data_pdu()|.
! 49: *
! 50: * |Established| state means that BIRD has synced all data with cache server.
! 51: * Schedules a refresh timer event that invokes |Sync-Start|. Schedules Expire
! 52: * timer event and stops a Retry timer event.
! 53: *
! 54: * |Transport Error| state means that we have some troubles with a network
! 55: * connection. We cannot connect to a cache server or we wait too long for some
! 56: * expected PDU for received - |Cache Response| or |End of Data|. It closes
! 57: * current connection and schedules a Retry timer event.
! 58: *
! 59: * |Fatal Protocol Error| is occurred e.g. by received a bad Session ID. We
! 60: * restart a protocol, so all ROAs are flushed immediately.
! 61: *
! 62: * The RPKI-RTR protocol (RFC 6810 bis) defines configurable refresh, retry and
! 63: * expire intervals. For maintaining a connection are used timer events that
! 64: * are scheduled by |rpki_schedule_next_refresh()|,
! 65: * |rpki_schedule_next_retry()| and |rpki_schedule_next_expire()| functions.
! 66: *
! 67: * A Refresh timer event performs a sync of |Established| connection. So it
! 68: * shifts state to |Sync-Start|. If at the beginning of second call of a
! 69: * refresh event is connection in |Sync-Start| state then we didn't receive a
! 70: * |Cache Response| from a cache server and we invoke |Transport Error| state.
! 71: *
! 72: * A Retry timer event attempts to connect cache server. It is activated after
! 73: * |Transport Error| state and terminated by reaching |Established| state.
! 74: * If cache connection is still connecting to the cache server at the beginning
! 75: * of an event call then the Retry timer event invokes |Transport Error| state.
! 76: *
! 77: * An Expire timer event checks expiration of ROAs. If a last successful sync
! 78: * was more ago than the expire interval then the Expire timer event invokes a
! 79: * protocol restart thereby removes all ROAs learned from that cache server and
! 80: * continue trying to connect to cache server. The Expire event is activated
! 81: * by initial successful loading of ROAs, receiving End of Data PDU.
! 82: *
! 83: * A reconfiguration of cache connection works well without restarting when we
! 84: * change only intervals values.
! 85: *
! 86: * Supported standards:
! 87: * - RFC 6810 - main RPKI-RTR standard
! 88: * - RFC 6810 bis - an explicit timing parameters and protocol version number negotiation
! 89: */
! 90:
! 91: #include <stdlib.h>
! 92: #include <netdb.h>
! 93:
! 94: #undef LOCAL_DEBUG
! 95:
! 96: #include "rpki.h"
! 97: #include "lib/string.h"
! 98: #include "nest/cli.h"
! 99:
! 100: /* Return values for reconfiguration functions */
! 101: #define NEED_RESTART 0
! 102: #define SUCCESSFUL_RECONF 1
! 103:
! 104: static int rpki_open_connection(struct rpki_cache *cache);
! 105: static void rpki_close_connection(struct rpki_cache *cache);
! 106: static void rpki_schedule_next_refresh(struct rpki_cache *cache);
! 107: static void rpki_schedule_next_retry(struct rpki_cache *cache);
! 108: static void rpki_schedule_next_expire_check(struct rpki_cache *cache);
! 109: static void rpki_stop_refresh_timer_event(struct rpki_cache *cache);
! 110: static void rpki_stop_retry_timer_event(struct rpki_cache *cache);
! 111: static void rpki_stop_expire_timer_event(struct rpki_cache *cache);
! 112:
! 113:
! 114: /*
! 115: * Routes handling
! 116: */
! 117:
! 118: void
! 119: rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr)
! 120: {
! 121: struct rpki_proto *p = cache->p;
! 122:
! 123: rta a0 = {
! 124: .src = p->p.main_source,
! 125: .source = RTS_RPKI,
! 126: .scope = SCOPE_UNIVERSE,
! 127: .dest = RTD_NONE,
! 128: };
! 129:
! 130: rta *a = rta_lookup(&a0);
! 131: rte *e = rte_get_temp(a);
! 132:
! 133: e->pflags = 0;
! 134:
! 135: rte_update2(channel, &pfxr->n, e, a0.src);
! 136: }
! 137:
! 138: void
! 139: rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr)
! 140: {
! 141: struct rpki_proto *p = cache->p;
! 142: rte_update2(channel, &pfxr->n, NULL, p->p.main_source);
! 143: }
! 144:
! 145:
! 146: /*
! 147: * RPKI Protocol Logic
! 148: */
! 149:
! 150: static const char *str_cache_states[] = {
! 151: [RPKI_CS_CONNECTING] = "Connecting",
! 152: [RPKI_CS_ESTABLISHED] = "Established",
! 153: [RPKI_CS_RESET] = "Reseting",
! 154: [RPKI_CS_SYNC_START] = "Sync-Start",
! 155: [RPKI_CS_SYNC_RUNNING] = "Sync-Running",
! 156: [RPKI_CS_FAST_RECONNECT] = "Fast-Reconnect",
! 157: [RPKI_CS_NO_INCR_UPDATE_AVAIL]= "No-Increment-Update-Available",
! 158: [RPKI_CS_ERROR_NO_DATA_AVAIL] = "Cache-Error-No-Data-Available",
! 159: [RPKI_CS_ERROR_FATAL] = "Fatal-Protocol-Error",
! 160: [RPKI_CS_ERROR_TRANSPORT] = "Transport-Error",
! 161: [RPKI_CS_SHUTDOWN] = "Down"
! 162: };
! 163:
! 164: /**
! 165: * rpki_cache_state_to_str - give a text representation of cache state
! 166: * @state: A cache state
! 167: *
! 168: * The function converts logic cache state into string.
! 169: */
! 170: const char *
! 171: rpki_cache_state_to_str(enum rpki_cache_state state)
! 172: {
! 173: return str_cache_states[state];
! 174: }
! 175:
! 176: /**
! 177: * rpki_start_cache - connect to a cache server
! 178: * @cache: RPKI connection instance
! 179: *
! 180: * This function is a high level method to kick up a connection to a cache server.
! 181: */
! 182: static void
! 183: rpki_start_cache(struct rpki_cache *cache)
! 184: {
! 185: rpki_cache_change_state(cache, RPKI_CS_CONNECTING);
! 186: }
! 187:
! 188: /**
! 189: * rpki_force_restart_proto - force shutdown and start protocol again
! 190: * @p: RPKI protocol instance
! 191: *
! 192: * This function calls shutdown and frees all protocol resources as well.
! 193: * After calling this function should be no operations with protocol data,
! 194: * they could be freed already.
! 195: */
! 196: static void
! 197: rpki_force_restart_proto(struct rpki_proto *p)
! 198: {
! 199: if (p->cache)
! 200: {
! 201: CACHE_DBG(p->cache, "Connection object destroying");
! 202: }
! 203:
! 204: /* Sign as freed */
! 205: p->cache = NULL;
! 206:
! 207: proto_notify_state(&p->p, PS_DOWN);
! 208: }
! 209:
! 210: /**
! 211: * rpki_cache_change_state - check and change cache state
! 212: * @cache: RPKI cache instance
! 213: * @new_state: suggested new state
! 214: *
! 215: * This function makes transitions between internal states.
! 216: * It represents the core of logic management of RPKI protocol.
! 217: * Cannot transit into the same state as cache is in already.
! 218: */
! 219: void
! 220: rpki_cache_change_state(struct rpki_cache *cache, const enum rpki_cache_state new_state)
! 221: {
! 222: const enum rpki_cache_state old_state = cache->state;
! 223:
! 224: if (old_state == new_state)
! 225: return;
! 226:
! 227: cache->state = new_state;
! 228: CACHE_TRACE(D_EVENTS, cache, "Changing from %s to %s state", rpki_cache_state_to_str(old_state), rpki_cache_state_to_str(new_state));
! 229:
! 230: switch (new_state)
! 231: {
! 232: case RPKI_CS_CONNECTING:
! 233: {
! 234: sock *sk = cache->tr_sock->sk;
! 235:
! 236: if (sk == NULL || sk->fd < 0)
! 237: rpki_open_connection(cache);
! 238: else
! 239: rpki_cache_change_state(cache, RPKI_CS_SYNC_START);
! 240:
! 241: rpki_schedule_next_retry(cache);
! 242: break;
! 243: }
! 244:
! 245: case RPKI_CS_ESTABLISHED:
! 246: rpki_schedule_next_refresh(cache);
! 247: rpki_schedule_next_expire_check(cache);
! 248: rpki_stop_retry_timer_event(cache);
! 249: break;
! 250:
! 251: case RPKI_CS_RESET:
! 252: /* Resetting cache connection. */
! 253: cache->request_session_id = 1;
! 254: cache->serial_num = 0;
! 255: rpki_cache_change_state(cache, RPKI_CS_SYNC_START);
! 256: break;
! 257:
! 258: case RPKI_CS_SYNC_START:
! 259: /* Requesting for receive ROAs from a cache server. */
! 260: if (cache->request_session_id)
! 261: {
! 262: /* Send request for Session ID */
! 263: if (rpki_send_reset_query(cache) != RPKI_SUCCESS)
! 264: rpki_cache_change_state(cache, RPKI_CS_ERROR_TRANSPORT);
! 265: }
! 266: else
! 267: {
! 268: /* We have already a session_id. So send a Serial Query and start an incremental sync */
! 269: if (rpki_send_serial_query(cache) != RPKI_SUCCESS)
! 270: rpki_cache_change_state(cache, RPKI_CS_ERROR_TRANSPORT);
! 271: }
! 272: break;
! 273:
! 274: case RPKI_CS_SYNC_RUNNING:
! 275: /* The state between Cache Response and End of Data. Only waiting for
! 276: * receiving all IP Prefix PDUs and finally a End of Data PDU. */
! 277: break;
! 278:
! 279: case RPKI_CS_NO_INCR_UPDATE_AVAIL:
! 280: /* Server was unable to answer the last Serial Query and sent Cache Reset. */
! 281: rpki_cache_change_state(cache, RPKI_CS_RESET);
! 282: break;
! 283:
! 284: case RPKI_CS_ERROR_NO_DATA_AVAIL:
! 285: /* No validation records are available on the cache server. */
! 286: rpki_cache_change_state(cache, RPKI_CS_RESET);
! 287: break;
! 288:
! 289: case RPKI_CS_ERROR_FATAL:
! 290: /* Fatal protocol error occurred. */
! 291: rpki_force_restart_proto(cache->p);
! 292: break;
! 293:
! 294: case RPKI_CS_ERROR_TRANSPORT:
! 295: /* Error on the transport socket occurred. */
! 296: rpki_close_connection(cache);
! 297: rpki_schedule_next_retry(cache);
! 298: rpki_stop_refresh_timer_event(cache);
! 299: break;
! 300:
! 301: case RPKI_CS_FAST_RECONNECT:
! 302: /* Reconnect without any waiting period */
! 303: rpki_close_connection(cache);
! 304: rpki_cache_change_state(cache, RPKI_CS_CONNECTING);
! 305: break;
! 306:
! 307: case RPKI_CS_SHUTDOWN:
! 308: bug("This isn't never really called.");
! 309: break;
! 310: };
! 311: }
! 312:
! 313:
! 314: /*
! 315: * RPKI Timer Events
! 316: */
! 317:
! 318: static void
! 319: rpki_schedule_next_refresh(struct rpki_cache *cache)
! 320: {
! 321: btime t = cache->refresh_interval S;
! 322:
! 323: CACHE_DBG(cache, "after %t s", t);
! 324: tm_start(cache->refresh_timer, t);
! 325: }
! 326:
! 327: static void
! 328: rpki_schedule_next_retry(struct rpki_cache *cache)
! 329: {
! 330: btime t = cache->retry_interval S;
! 331:
! 332: CACHE_DBG(cache, "after %t s", t);
! 333: tm_start(cache->retry_timer, t);
! 334: }
! 335:
! 336: static void
! 337: rpki_schedule_next_expire_check(struct rpki_cache *cache)
! 338: {
! 339: /* A minimum time to wait is 1 second */
! 340: btime t = cache->last_update + cache->expire_interval S - current_time();
! 341: t = MAX(t, 1 S);
! 342:
! 343: CACHE_DBG(cache, "after %t s", t);
! 344: tm_start(cache->expire_timer, t);
! 345: }
! 346:
! 347: static void
! 348: rpki_stop_refresh_timer_event(struct rpki_cache *cache)
! 349: {
! 350: CACHE_DBG(cache, "Stop");
! 351: tm_stop(cache->refresh_timer);
! 352: }
! 353:
! 354: static void
! 355: rpki_stop_retry_timer_event(struct rpki_cache *cache)
! 356: {
! 357: CACHE_DBG(cache, "Stop");
! 358: tm_stop(cache->retry_timer);
! 359: }
! 360:
! 361: static void UNUSED
! 362: rpki_stop_expire_timer_event(struct rpki_cache *cache)
! 363: {
! 364: CACHE_DBG(cache, "Stop");
! 365: tm_stop(cache->expire_timer);
! 366: }
! 367:
! 368: static int
! 369: rpki_do_we_recv_prefix_pdu_in_last_seconds(struct rpki_cache *cache)
! 370: {
! 371: if (!cache->last_rx_prefix)
! 372: return 0;
! 373:
! 374: return ((current_time() - cache->last_rx_prefix) <= 2 S);
! 375: }
! 376:
! 377: /**
! 378: * rpki_refresh_hook - control a scheduling of downloading data from cache server
! 379: * @tm: refresh timer with cache connection instance in data
! 380: *
! 381: * This function is periodically called during &ESTABLISHED or &SYNC* state
! 382: * cache connection. The first refresh schedule is invoked after receiving a
! 383: * |End of Data| PDU and has run by some &ERROR is occurred.
! 384: */
! 385: static void
! 386: rpki_refresh_hook(timer *tm)
! 387: {
! 388: struct rpki_cache *cache = tm->data;
! 389:
! 390: CACHE_DBG(cache, "%s", rpki_cache_state_to_str(cache->state));
! 391:
! 392: switch (cache->state)
! 393: {
! 394: case RPKI_CS_ESTABLISHED:
! 395: rpki_cache_change_state(cache, RPKI_CS_SYNC_START);
! 396: break;
! 397:
! 398: case RPKI_CS_SYNC_START:
! 399: /* We sent Serial/Reset Query in last refresh hook call
! 400: * and didn't receive Cache Response yet. It is probably
! 401: * troubles with network. */
! 402: case RPKI_CS_SYNC_RUNNING:
! 403: /* We sent Serial/Reset Query in last refresh hook call
! 404: * and we got Cache Response but didn't get End-Of-Data yet.
! 405: * It could be a trouble with network or only too long synchronization. */
! 406: if (!rpki_do_we_recv_prefix_pdu_in_last_seconds(cache))
! 407: {
! 408: CACHE_TRACE(D_EVENTS, cache, "Sync takes more time than refresh interval %us, resetting connection", cache->refresh_interval);
! 409: rpki_cache_change_state(cache, RPKI_CS_ERROR_TRANSPORT);
! 410: }
! 411: break;
! 412:
! 413: default:
! 414: break;
! 415: }
! 416:
! 417: if (cache->state != RPKI_CS_SHUTDOWN && cache->state != RPKI_CS_ERROR_TRANSPORT)
! 418: rpki_schedule_next_refresh(cache);
! 419: else
! 420: rpki_stop_refresh_timer_event(cache);
! 421: }
! 422:
! 423: /**
! 424: * rpki_retry_hook - control a scheduling of retrying connection to cache server
! 425: * @tm: retry timer with cache connection instance in data
! 426: *
! 427: * This function is periodically called during &ERROR* state cache connection.
! 428: * The first retry schedule is invoked after any &ERROR* state occurred and
! 429: * ends by reaching of &ESTABLISHED state again.
! 430: */
! 431: static void
! 432: rpki_retry_hook(timer *tm)
! 433: {
! 434: struct rpki_cache *cache = tm->data;
! 435:
! 436: CACHE_DBG(cache, "%s", rpki_cache_state_to_str(cache->state));
! 437:
! 438: switch (cache->state)
! 439: {
! 440: case RPKI_CS_ESTABLISHED:
! 441: case RPKI_CS_SHUTDOWN:
! 442: break;
! 443:
! 444: case RPKI_CS_CONNECTING:
! 445: case RPKI_CS_SYNC_START:
! 446: case RPKI_CS_SYNC_RUNNING:
! 447: if (!rpki_do_we_recv_prefix_pdu_in_last_seconds(cache))
! 448: {
! 449: /* We tried to establish a connection in last retry hook call and haven't done
! 450: * yet. It looks like troubles with network. We are aggressive here. */
! 451: CACHE_TRACE(D_EVENTS, cache, "Sync takes more time than retry interval %us, resetting connection.", cache->retry_interval);
! 452: rpki_cache_change_state(cache, RPKI_CS_ERROR_TRANSPORT);
! 453: }
! 454: break;
! 455:
! 456: default:
! 457: rpki_cache_change_state(cache, RPKI_CS_CONNECTING);
! 458: break;
! 459: }
! 460:
! 461: if (cache->state != RPKI_CS_ESTABLISHED)
! 462: rpki_schedule_next_retry(cache);
! 463: else
! 464: rpki_stop_retry_timer_event(cache);
! 465: }
! 466:
! 467: /**
! 468: * rpki_expire_hook - control a expiration of ROA entries
! 469: * @tm: expire timer with cache connection instance in data
! 470: *
! 471: * This function is scheduled after received a |End of Data| PDU.
! 472: * A waiting interval is calculated dynamically by last update.
! 473: * If we reach an expiration time then we invoke a restarting
! 474: * of the protocol.
! 475: */
! 476: static void
! 477: rpki_expire_hook(timer *tm)
! 478: {
! 479: struct rpki_cache *cache = tm->data;
! 480:
! 481: if (!cache->last_update)
! 482: return;
! 483:
! 484: CACHE_DBG(cache, "%s", rpki_cache_state_to_str(cache->state));
! 485:
! 486: btime t = cache->last_update + cache->expire_interval S - current_time();
! 487: if (t <= 0)
! 488: {
! 489: CACHE_TRACE(D_EVENTS, cache, "All ROAs expired");
! 490: rpki_force_restart_proto(cache->p);
! 491: }
! 492: else
! 493: {
! 494: CACHE_DBG(cache, "Remains %t seconds to become ROAs obsolete", t);
! 495: rpki_schedule_next_expire_check(cache);
! 496: }
! 497: }
! 498:
! 499: /**
! 500: * rpki_check_refresh_interval - check validity of refresh interval value
! 501: * @seconds: suggested value
! 502: *
! 503: * This function validates value and should return |NULL|.
! 504: * If the check doesn't pass then returns error message.
! 505: */
! 506: const char *
! 507: rpki_check_refresh_interval(uint seconds)
! 508: {
! 509: if (seconds < 1)
! 510: return "Minimum allowed refresh interval is 1 second";
! 511: if (seconds > 86400)
! 512: return "Maximum allowed refresh interval is 86400 seconds";
! 513: return NULL;
! 514: }
! 515:
! 516: /**
! 517: * rpki_check_retry_interval - check validity of retry interval value
! 518: * @seconds: suggested value
! 519: *
! 520: * This function validates value and should return |NULL|.
! 521: * If the check doesn't pass then returns error message.
! 522: */
! 523: const char *
! 524: rpki_check_retry_interval(uint seconds)
! 525: {
! 526: if (seconds < 1)
! 527: return "Minimum allowed retry interval is 1 second";
! 528: if (seconds > 7200)
! 529: return "Maximum allowed retry interval is 7200 seconds";
! 530: return NULL;
! 531: }
! 532:
! 533: /**
! 534: * rpki_check_expire_interval - check validity of expire interval value
! 535: * @seconds: suggested value
! 536: *
! 537: * This function validates value and should return |NULL|.
! 538: * If the check doesn't pass then returns error message.
! 539: */
! 540: const char *
! 541: rpki_check_expire_interval(uint seconds)
! 542: {
! 543: if (seconds < 600)
! 544: return "Minimum allowed expire interval is 600 seconds";
! 545: if (seconds > 172800)
! 546: return "Maximum allowed expire interval is 172800 seconds";
! 547: return NULL;
! 548: }
! 549:
! 550:
! 551: /*
! 552: * RPKI Cache
! 553: */
! 554:
! 555: static struct rpki_cache *
! 556: rpki_init_cache(struct rpki_proto *p, struct rpki_config *cf)
! 557: {
! 558: pool *pool = rp_new(p->p.pool, cf->hostname);
! 559:
! 560: struct rpki_cache *cache = mb_allocz(pool, sizeof(struct rpki_cache));
! 561:
! 562: cache->pool = pool;
! 563: cache->p = p;
! 564:
! 565: cache->state = RPKI_CS_SHUTDOWN;
! 566: cache->request_session_id = 1;
! 567: cache->version = RPKI_MAX_VERSION;
! 568:
! 569: cache->refresh_interval = cf->refresh_interval;
! 570: cache->retry_interval = cf->retry_interval;
! 571: cache->expire_interval = cf->expire_interval;
! 572: cache->refresh_timer = tm_new_init(pool, &rpki_refresh_hook, cache, 0, 0);
! 573: cache->retry_timer = tm_new_init(pool, &rpki_retry_hook, cache, 0, 0);
! 574: cache->expire_timer = tm_new_init(pool, &rpki_expire_hook, cache, 0, 0);
! 575:
! 576: cache->tr_sock = mb_allocz(pool, sizeof(struct rpki_tr_sock));
! 577: cache->tr_sock->cache = cache;
! 578:
! 579: switch (cf->tr_config.type)
! 580: {
! 581: case RPKI_TR_TCP: rpki_tr_tcp_init(cache->tr_sock); break;
! 582: case RPKI_TR_SSH: rpki_tr_ssh_init(cache->tr_sock); break;
! 583: };
! 584:
! 585: CACHE_DBG(cache, "Connection object created");
! 586:
! 587: return cache;
! 588: }
! 589:
! 590: /**
! 591: * rpki_get_cache_ident - give a text representation of cache server name
! 592: * @cache: RPKI connection instance
! 593: *
! 594: * The function converts cache connection into string.
! 595: */
! 596: const char *
! 597: rpki_get_cache_ident(struct rpki_cache *cache)
! 598: {
! 599: return rpki_tr_ident(cache->tr_sock);
! 600: }
! 601:
! 602: static int
! 603: rpki_open_connection(struct rpki_cache *cache)
! 604: {
! 605: CACHE_TRACE(D_EVENTS, cache, "Opening a connection");
! 606:
! 607: if (rpki_tr_open(cache->tr_sock) == RPKI_TR_ERROR)
! 608: {
! 609: rpki_cache_change_state(cache, RPKI_CS_ERROR_TRANSPORT);
! 610: return RPKI_TR_ERROR;
! 611: }
! 612:
! 613: return RPKI_TR_SUCCESS;
! 614: }
! 615:
! 616: static void
! 617: rpki_close_connection(struct rpki_cache *cache)
! 618: {
! 619: CACHE_TRACE(D_EVENTS, cache, "Closing a connection");
! 620: rpki_tr_close(cache->tr_sock);
! 621: proto_notify_state(&cache->p->p, PS_START);
! 622: }
! 623:
! 624: static int
! 625: rpki_shutdown(struct proto *P)
! 626: {
! 627: struct rpki_proto *p = (void *) P;
! 628:
! 629: rpki_force_restart_proto(p);
! 630:
! 631: /* Protocol memory pool will be automatically freed */
! 632: return PS_DOWN;
! 633: }
! 634:
! 635:
! 636: /*
! 637: * RPKI Reconfiguration
! 638: */
! 639:
! 640: static int
! 641: rpki_try_fast_reconnect(struct rpki_cache *cache)
! 642: {
! 643: if (cache->state == RPKI_CS_ESTABLISHED)
! 644: {
! 645: rpki_cache_change_state(cache, RPKI_CS_FAST_RECONNECT);
! 646: return SUCCESSFUL_RECONF;
! 647: }
! 648:
! 649: return NEED_RESTART;
! 650: }
! 651:
! 652: /**
! 653: * rpki_reconfigure_cache - a cache reconfiguration
! 654: * @p: RPKI protocol instance
! 655: * @cache: a cache connection
! 656: * @new: new RPKI configuration
! 657: * @old: old RPKI configuration
! 658: *
! 659: * This function reconfigures existing single cache server connection with new
! 660: * existing configuration. Generally, a change of time intervals could be
! 661: * reconfigured without restarting and all others changes requires a restart of
! 662: * protocol. Returns |NEED_TO_RESTART| or |SUCCESSFUL_RECONF|.
! 663: */
! 664: static int
! 665: rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old)
! 666: {
! 667: u8 try_fast_reconnect = 0;
! 668:
! 669: if (strcmp(old->hostname, new->hostname) != 0)
! 670: {
! 671: CACHE_TRACE(D_EVENTS, cache, "Cache server address changed to %s", new->hostname);
! 672: return NEED_RESTART;
! 673: }
! 674:
! 675: if (old->port != new->port)
! 676: {
! 677: CACHE_TRACE(D_EVENTS, cache, "Cache server port changed to %u", new->port);
! 678: return NEED_RESTART;
! 679: }
! 680:
! 681: if (old->tr_config.type != new->tr_config.type)
! 682: {
! 683: CACHE_TRACE(D_EVENTS, cache, "Transport type changed");
! 684: return NEED_RESTART;
! 685: }
! 686: else if (new->tr_config.type == RPKI_TR_SSH)
! 687: {
! 688: struct rpki_tr_ssh_config *ssh_old = (void *) old->tr_config.spec;
! 689: struct rpki_tr_ssh_config *ssh_new = (void *) new->tr_config.spec;
! 690: if (bstrcmp(ssh_old->bird_private_key, ssh_new->bird_private_key) ||
! 691: bstrcmp(ssh_old->cache_public_key, ssh_new->cache_public_key) ||
! 692: bstrcmp(ssh_old->user, ssh_new->user))
! 693: {
! 694: CACHE_TRACE(D_EVENTS, cache, "Settings of SSH transport configuration changed");
! 695: try_fast_reconnect = 1;
! 696: }
! 697: }
! 698:
! 699: #define TEST_INTERVAL(name, Name) \
! 700: if (cache->name##_interval != new->name##_interval || \
! 701: old->keep_##name##_interval != new->keep_##name##_interval) \
! 702: { \
! 703: cache->name##_interval = new->name##_interval; \
! 704: CACHE_TRACE(D_EVENTS, cache, #Name " interval changed to %u seconds %s", cache->name##_interval, (new->keep_##name##_interval ? "and keep it" : "")); \
! 705: try_fast_reconnect = 1; \
! 706: }
! 707: TEST_INTERVAL(refresh, Refresh);
! 708: TEST_INTERVAL(retry, Retry);
! 709: TEST_INTERVAL(expire, Expire);
! 710: #undef TEST_INTERVAL
! 711:
! 712: if (try_fast_reconnect)
! 713: return rpki_try_fast_reconnect(cache);
! 714:
! 715: return SUCCESSFUL_RECONF;
! 716: }
! 717:
! 718: /**
! 719: * rpki_reconfigure - a protocol reconfiguration hook
! 720: * @P: a protocol instance
! 721: * @CF: a new protocol configuration
! 722: *
! 723: * This function reconfigures whole protocol.
! 724: * It sets new protocol configuration into a protocol structure.
! 725: * Returns |NEED_TO_RESTART| or |SUCCESSFUL_RECONF|.
! 726: */
! 727: static int
! 728: rpki_reconfigure(struct proto *P, struct proto_config *CF)
! 729: {
! 730: struct rpki_proto *p = (void *) P;
! 731: struct rpki_config *new = (void *) CF;
! 732: struct rpki_config *old = (void *) p->p.cf;
! 733: struct rpki_cache *cache = p->cache;
! 734:
! 735: if (!proto_configure_channel(&p->p, &p->roa4_channel, proto_cf_find_channel(CF, NET_ROA4)) ||
! 736: !proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6)))
! 737: return NEED_RESTART;
! 738:
! 739: if (rpki_reconfigure_cache(p, cache, new, old) != SUCCESSFUL_RECONF)
! 740: return NEED_RESTART;
! 741:
! 742: return SUCCESSFUL_RECONF;
! 743: }
! 744:
! 745:
! 746: /*
! 747: * RPKI Protocol Glue
! 748: */
! 749:
! 750: static struct proto *
! 751: rpki_init(struct proto_config *CF)
! 752: {
! 753: struct proto *P = proto_new(CF);
! 754: struct rpki_proto *p = (void *) P;
! 755:
! 756: proto_configure_channel(&p->p, &p->roa4_channel, proto_cf_find_channel(CF, NET_ROA4));
! 757: proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6));
! 758:
! 759: return P;
! 760: }
! 761:
! 762: static int
! 763: rpki_start(struct proto *P)
! 764: {
! 765: struct rpki_proto *p = (void *) P;
! 766: struct rpki_config *cf = (void *) P->cf;
! 767:
! 768: p->cache = rpki_init_cache(p, cf);
! 769: rpki_start_cache(p->cache);
! 770:
! 771: return PS_START;
! 772: }
! 773:
! 774: static void
! 775: rpki_get_status(struct proto *P, byte *buf)
! 776: {
! 777: struct rpki_proto *p = (struct rpki_proto *) P;
! 778:
! 779: if (P->proto_state == PS_DOWN)
! 780: {
! 781: *buf = 0;
! 782: return;
! 783: }
! 784:
! 785: if (p->cache)
! 786: bsprintf(buf, "%s", rpki_cache_state_to_str(p->cache->state));
! 787: else
! 788: bsprintf(buf, "No cache server configured");
! 789: }
! 790:
! 791: static void
! 792: rpki_show_proto_info_timer(const char *name, uint num, timer *t)
! 793: {
! 794: if (tm_active(t))
! 795: cli_msg(-1006, " %-16s: %t/%u", name, tm_remains(t), num);
! 796: else
! 797: cli_msg(-1006, " %-16s: ---", name);
! 798: }
! 799:
! 800: static void
! 801: rpki_show_proto_info(struct proto *P)
! 802: {
! 803: struct rpki_proto *p = (struct rpki_proto *) P;
! 804: struct rpki_config *cf = (void *) p->p.cf;
! 805: struct rpki_cache *cache = p->cache;
! 806:
! 807: if (P->proto_state == PS_DOWN)
! 808: return;
! 809:
! 810: if (cache)
! 811: {
! 812: const char *transport_name = "---";
! 813:
! 814: switch (cf->tr_config.type)
! 815: {
! 816: case RPKI_TR_SSH: transport_name = "SSHv2"; break;
! 817: case RPKI_TR_TCP: transport_name = "Unprotected over TCP"; break;
! 818: };
! 819:
! 820: cli_msg(-1006, " Cache server: %s", rpki_get_cache_ident(cache));
! 821: cli_msg(-1006, " Status: %s", rpki_cache_state_to_str(cache->state));
! 822: cli_msg(-1006, " Transport: %s", transport_name);
! 823: cli_msg(-1006, " Protocol version: %u", cache->version);
! 824:
! 825: if (cache->request_session_id)
! 826: cli_msg(-1006, " Session ID: ---");
! 827: else
! 828: cli_msg(-1006, " Session ID: %u", cache->session_id);
! 829:
! 830: if (cache->last_update)
! 831: {
! 832: cli_msg(-1006, " Serial number: %u", cache->serial_num);
! 833: cli_msg(-1006, " Last update: before %t s", current_time() - cache->last_update);
! 834: }
! 835: else
! 836: {
! 837: cli_msg(-1006, " Serial number: ---");
! 838: cli_msg(-1006, " Last update: ---");
! 839: }
! 840:
! 841: rpki_show_proto_info_timer("Refresh timer", cache->refresh_interval, cache->refresh_timer);
! 842: rpki_show_proto_info_timer("Retry timer", cache->retry_interval, cache->retry_timer);
! 843: rpki_show_proto_info_timer("Expire timer", cache->expire_interval, cache->expire_timer);
! 844:
! 845: if (p->roa4_channel)
! 846: channel_show_info(p->roa4_channel);
! 847: else
! 848: cli_msg(-1006, " No roa4 channel");
! 849:
! 850: if (p->roa6_channel)
! 851: channel_show_info(p->roa6_channel);
! 852: else
! 853: cli_msg(-1006, " No roa6 channel");
! 854: }
! 855: }
! 856:
! 857:
! 858: /*
! 859: * RPKI Protocol Configuration
! 860: */
! 861:
! 862: /**
! 863: * rpki_check_config - check and complete configuration of RPKI protocol
! 864: * @cf: RPKI configuration
! 865: *
! 866: * This function is called at the end of parsing RPKI protocol configuration.
! 867: */
! 868: void
! 869: rpki_check_config(struct rpki_config *cf)
! 870: {
! 871: /* Do not check templates at all */
! 872: if (cf->c.class == SYM_TEMPLATE)
! 873: return;
! 874:
! 875: if (ipa_zero(cf->ip) && cf->hostname == NULL)
! 876: cf_error("IP address or hostname of cache server must be set");
! 877:
! 878: /* Set default transport type */
! 879: if (cf->tr_config.spec == NULL)
! 880: {
! 881: cf->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_tcp_config));
! 882: cf->tr_config.type = RPKI_TR_TCP;
! 883: }
! 884:
! 885: if (cf->port == 0)
! 886: {
! 887: /* Set default port numbers */
! 888: switch (cf->tr_config.type)
! 889: {
! 890: case RPKI_TR_SSH:
! 891: cf->port = RPKI_SSH_PORT;
! 892: break;
! 893: default:
! 894: cf->port = RPKI_TCP_PORT;
! 895: }
! 896: }
! 897: }
! 898:
! 899: static void
! 900: rpki_postconfig(struct proto_config *CF)
! 901: {
! 902: /* Define default channel */
! 903: if (EMPTY_LIST(CF->channels))
! 904: channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
! 905: }
! 906:
! 907: static void
! 908: rpki_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
! 909: {
! 910: /* FIXME: Should copy transport */
! 911: }
! 912:
! 913: struct protocol proto_rpki = {
! 914: .name = "RPKI",
! 915: .template = "rpki%d",
! 916: .class = PROTOCOL_RPKI,
! 917: .preference = DEF_PREF_RPKI,
! 918: .proto_size = sizeof(struct rpki_proto),
! 919: .config_size = sizeof(struct rpki_config),
! 920: .init = rpki_init,
! 921: .start = rpki_start,
! 922: .postconfig = rpki_postconfig,
! 923: .channel_mask = (NB_ROA4 | NB_ROA6),
! 924: .show_proto_info = rpki_show_proto_info,
! 925: .shutdown = rpki_shutdown,
! 926: .copy_config = rpki_copy_config,
! 927: .reconfigure = rpki_reconfigure,
! 928: .get_status = rpki_get_status,
! 929: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>