Index: proto/bgp/bgp.c =================================================================== --- proto/bgp/bgp.c (revision 4980) +++ proto/bgp/bgp.c (working copy) @@ -93,6 +93,7 @@ { struct config *cfg = p->cf->c.global; bgp_counter++; + int errcause; if (!bgp_listen_sk) bgp_listen_sk = bgp_setup_listen_sk(cfg->listen_bgp_addr, cfg->listen_bgp_port, cfg->listen_bgp_flags); @@ -100,10 +101,8 @@ if (!bgp_listen_sk) { bgp_counter--; - p->p.disabled = 1; - bgp_store_error(p, NULL, BE_MISC, BEM_NO_SOCKET); - proto_notify_state(&p->p, PS_DOWN); - return -1; + errcause = BEM_NO_SOCKET; + goto err; } if (!bgp_linpool) @@ -115,14 +114,17 @@ if (rv < 0) { bgp_close(p, 0); - p->p.disabled = 1; - bgp_store_error(p, NULL, BE_MISC, BEM_INVALID_MD5); - proto_notify_state(&p->p, PS_DOWN); - return -1; + goto err; } } return 0; + +err: + p->p.disabled = 1; + bgp_store_error(p, NULL, BE_MISC, errcause); + proto_notify_state(&p->p, PS_DOWN); + return -1; } static void @@ -574,7 +576,11 @@ s->saddr = p->source_addr; s->daddr = p->cf->remote_ip; s->dport = BGP_PORT; - s->ttl = p->cf->multihop ? : 1; + /* TTL security support */ + if (p->cf->ttl_sec_hops) + s->ttl = 255; + else + s->ttl = p->cf->multihop ? : 1; s->rbsize = BGP_RX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE; s->tos = IP_PREC_INTERNET_CONTROL; @@ -589,6 +595,17 @@ bgp_sock_err(s, 0); return; } + /* Set minimal receive TTL if needed */ + if (p->cf->ttl_sec_hops) + { + DBG("Setting minimum received TTL to %d", 256 - p->cf->ttl_sec_hops); + if (sk_set_min_ttl(s, 256 - p->cf->ttl_sec_hops) < 0) + { + log(L_ERR "TTL security configuration failed, closing session"); + bgp_sock_err(s, 0); + return; + } + } DBG("BGP: Waiting for connect success\n"); bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time); } @@ -629,7 +646,17 @@ bgp_setup_conn(p, &p->incoming_conn); bgp_setup_sk(&p->incoming_conn, sk); - sk_set_ttl(sk, p->cf->multihop ? : 1); + /* TTL security support */ + if (p->cf->ttl_sec_hops) + { + if ((sk_set_ttl(sk, 255) < 0) || (sk_set_min_ttl(sk, 256 - p->cf->ttl_sec_hops) < 0)) + { + log(L_ERR "TTL security configuration failed, closing session"); + goto err; + } + } + else + sk_set_ttl(sk, p->cf->multihop ? : 1); bgp_send_open(&p->incoming_conn); return 0; } @@ -656,6 +683,7 @@ sock *s = sk_new(&root_pool); DBG("BGP: Creating listening socket\n"); s->type = SK_TCP_PASSIVE; + s->ttl = 255; s->saddr = addr; s->sport = port ? port : BGP_PORT; s->flags = flags ? 0 : SKF_V6ONLY; @@ -670,8 +698,7 @@ rfree(s); return NULL; } - else - return s; + return s; } static void @@ -972,6 +999,12 @@ if (c->multihop && (c->gw_mode == GW_DIRECT)) cf_error("Multihop BGP cannot use direct gateway mode"); + if (c->ttl_sec_hops && ((c->ttl_sec_hops < 1) || (c->ttl_sec_hops > 254))) + cf_error("Wrong hops value for TTL security. Accepted: 1..254"); + + if (c->multihop && ((c->multihop < 1) || (c->multihop > 255))) + cf_error("Wrong multihop value. Accepted: 1..255"); + /* Different default based on rs_client */ if (!c->missing_lladdr) c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF; Index: proto/bgp/config.Y =================================================================== --- proto/bgp/config.Y (revision 4980) +++ proto/bgp/config.Y (working copy) @@ -25,7 +25,7 @@ ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE, - GATEWAY, DIRECT, RECURSIVE, MED) + GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, HOPS) CF_GRAMMAR @@ -98,6 +98,7 @@ | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; } + | bgp_proto TTL SECURITY HOPS expr ';' { BGP_CFG->ttl_sec_hops = $5; } ; CF_ADDTO(dynamic_attr, BGP_ORIGIN Index: proto/bgp/bgp.h =================================================================== --- proto/bgp/bgp.h (revision 4980) +++ proto/bgp/bgp.h (working copy) @@ -20,6 +20,7 @@ u32 local_as, remote_as; ip_addr remote_ip; int multihop; /* Number of hops if multihop */ + int ttl_sec_hops; /* Number of hops if TTL security is enabled */ ip_addr source_addr; /* Source address to use */ int next_hop_self; /* Always set next hop to local IP address */ int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */ Index: doc/bird.sgml =================================================================== --- doc/bird.sgml (revision 4980) +++ doc/bird.sgml (working copy) @@ -1136,6 +1136,14 @@ as an IGP routing table. Default: the same as the table BGP is connected to. + ttl security hops Use RFC 5082 (TTL security mechanism). + Maximum hop count has to be supplied. Note target PC (e.g. bird instance) + also counts as hop, so minimum hop count is 1. If ttl security is enabled + value supplied in password Use this password for MD5 authentication of BGP sessions. Default: no authentication. Password has to be set by external utility (e.g. setkey(8)) on BSD systems. Index: lib/socket.h =================================================================== --- lib/socket.h (revision 4980) +++ lib/socket.h (working copy) @@ -54,7 +54,8 @@ int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */ void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */ void sk_dump_all(void); -int sk_set_ttl(sock *s, int ttl); /* Set TTL for given socket */ +int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */ +int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */ /* Add or remove security associations for given passive socket */ int sk_set_md5_auth(sock *s, ip_addr a, char *passwd); Index: sysdep/linux/sysio.h =================================================================== --- sysdep/linux/sysio.h (revision 4980) +++ sysdep/linux/sysio.h (working copy) @@ -309,3 +309,35 @@ */ #endif + +#ifndef IP_MINTTL +#define IP_MINTTL 21 +#endif + +#ifndef IPV6_MINHOPCOUNT +#define IPV6_MINHOPCOUNT 73 +#endif + +static int +sk_set_min_ttl4(sock *s, int ttl) +{ + if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) == -1) + { + log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); + return -1; + } + + return 0; +} + +static int +sk_set_min_ttl6(sock *s, int ttl) +{ + if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_MINHOPCNT, &ttl, sizeof(ttl)) == -1) + { + log(L_ERR "sk_set_min_ttl6: setsockopt: %m"); + return -1; + } + + return 0; +} Index: sysdep/unix/io.c =================================================================== --- sysdep/unix/io.c (revision 4980) +++ sysdep/unix/io.c (working copy) @@ -805,7 +805,7 @@ } /** - * sk_set_ttl - set TTL for given socket. + * sk_set_ttl - set transmit TTL for given socket. * @s: socket * @ttl: TTL value * @@ -828,7 +828,29 @@ return (err ? -1 : 0); } +/** + * sk_set_min_ttl - set minimal accepted TTL for given socket. + * @s: socket + * @ttl: TTL value + * + * Can be used in TTL security implementation + * + * Result: 0 for success, -1 for an error. + */ +int +sk_set_min_ttl(sock *s, int ttl) +{ + int err; +#ifdef IPV6 + err = sk_set_min_ttl6(s, ttl); +#else + err = sk_set_min_ttl4(s, ttl); +#endif + + return err; +} + /** * sk_set_md5_auth - add / remove MD5 security association for given socket. * @s: socket Index: sysdep/bsd/sysio.h =================================================================== --- sysdep/bsd/sysio.h (revision 4980) +++ sysdep/bsd/sysio.h (working copy) @@ -237,3 +237,23 @@ return rv; } + +static int +sk_set_min_ttl4(sock *s, int ttl) +{ + if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) == -1) + { + log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); + return -1; + } + + return 0; +} + +static int +sk_set_min_ttl6(sock *s, int ttl) +{ + log(L_ERR "sk_set_min_ttl6: not supported"); + return -1; +} +