diff options
-rw-r--r-- | doc/bird.sgml | 20 | ||||
-rw-r--r-- | lib/socket.h | 3 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 62 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 1 | ||||
-rw-r--r-- | proto/bgp/config.Y | 5 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 31 | ||||
-rw-r--r-- | sysdep/linux/sysio.h | 48 | ||||
-rw-r--r-- | sysdep/unix/io.c | 24 | ||||
-rw-r--r-- | sysdep/unix/main.c | 1 |
9 files changed, 174 insertions, 21 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml index 406adc6..2435d1c 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1120,9 +1120,11 @@ for each neighbor using the following configuration parameters: subnets. Such IP address have to be reachable through system routing table. For multihop BGP it is recommended to explicitly configure <cf/source address/ to have it - stable. Optional <cf/number/ argument can be used to limit TTL - (the number of hops). - Default: switched off. + stable. Optional <cf/number/ argument can be used to specify + the number of hops (used for TTL). Note that the number of + networks (edges) in a path is counted, i.e. if two BGP + speakers are separated by one router, the number of hops is + 2. Default: switched off. <tag>source address <m/ip/</tag> Define local address we should use for next hop calculation and as a source address @@ -1169,6 +1171,18 @@ for each neighbor using the following configuration parameters: as an IGP routing table. Default: the same as the table BGP is connected to. + <tag>ttl security <m/switch/</tag> Use GTSM (RFC 5082 - the + generalized TTL security mechanism). GTSM protects against + spoofed packets by ignoring received packets with a smaller + than expected TTL. To work properly, GTSM have to be enabled + on both sides of a BGP session. If both <cf/ttl security/ and + <cf/multihop/ options are enabled, <cf/multihop/ option should + specify proper hop value to compute expected TTL. Kernel + support required: Linux: 2.6.34+ (IPv4), 2.6.35+ (IPv6), BSD: + since long ago, IPv4 only. Note that full (ICMP protection, + for example) RFC 5082 support is provided by Linux + only. Default: disabled. + <tag>password <m/string/</tag> 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. diff --git a/lib/socket.h b/lib/socket.h index 348295f..9b9452c 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -54,7 +54,8 @@ int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */ 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); diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 70c9b2f..d26b481 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -92,6 +92,8 @@ static int bgp_open(struct bgp_proto *p) { struct config *cfg = p->cf->c.global; + int errcode; + bgp_counter++; if (!bgp_listen_sk) @@ -100,10 +102,8 @@ bgp_open(struct bgp_proto *p) 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; + errcode = BEM_NO_SOCKET; + goto err; } if (!bgp_linpool) @@ -115,14 +115,18 @@ bgp_open(struct bgp_proto *p) 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; + errcode = BEM_INVALID_MD5; + goto err; } } return 0; + +err: + p->p.disabled = 1; + bgp_store_error(p, NULL, BE_MISC, errcode); + proto_notify_state(&p->p, PS_DOWN); + return -1; } static void @@ -567,6 +571,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c { sock *s; struct bgp_conn *conn = &p->outgoing_conn; + int hops = p->cf->multihop ? : 1; DBG("BGP: Connecting\n"); s = sk_new(p->p.pool); @@ -574,7 +579,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->saddr = p->source_addr; s->daddr = p->cf->remote_ip; s->dport = BGP_PORT; - s->ttl = p->cf->multihop ? : 1; + s->ttl = p->cf->ttl_security ? 255 : hops; s->rbsize = BGP_RX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE; s->tos = IP_PREC_INTERNET_CONTROL; @@ -584,11 +589,25 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c bgp_setup_conn(p, conn); bgp_setup_sk(conn, s); bgp_conn_set_state(conn, BS_CONNECT); - if (sk_open(s)) + + if (sk_open(s) < 0) { bgp_sock_err(s, 0); return; } + + /* Set minimal receive TTL if needed */ + if (p->cf->ttl_security) + { + DBG("Setting minimum received TTL to %d", 256 - hops); + if (sk_set_min_ttl(s, 256 - 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); } @@ -627,9 +646,22 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) if (!acc) goto err; + int hops = p->cf->multihop ? : 1; + if (p->cf->ttl_security) + { + /* TTL security support */ + if ((sk_set_ttl(sk, 255) < 0) || + (sk_set_min_ttl(sk, 256 - hops) < 0)) + { + log(L_ERR "TTL security configuration failed, closing session"); + goto err; + } + } + else + sk_set_ttl(sk, hops); + bgp_setup_conn(p, &p->incoming_conn); bgp_setup_sk(&p->incoming_conn, sk); - sk_set_ttl(sk, p->cf->multihop ? : 1); bgp_send_open(&p->incoming_conn); return 0; } @@ -656,6 +688,7 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags) 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; @@ -664,14 +697,15 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags) s->tbsize = BGP_TX_BUFFER_SIZE; s->rx_hook = bgp_incoming_connection; s->err_hook = bgp_listen_sock_err; - if (sk_open(s)) + + if (sk_open(s) < 0) { log(L_ERR "BGP: Unable to open listening socket"); rfree(s); return NULL; } - else - return s; + + return s; } static void diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 1247870..16e8ea8 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -20,6 +20,7 @@ struct bgp_config { u32 local_as, remote_as; ip_addr remote_ip; int multihop; /* Number of hops if multihop */ + int ttl_security; /* Enable TTL security [RFC5082] */ 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_* */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 93cc85f..19d757a 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -25,7 +25,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, CLUSTER, ID, AS4, 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) + TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY) CF_GRAMMAR @@ -71,7 +71,7 @@ bgp_proto: | bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; } | bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; } | bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; } - | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; } + | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); } | bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; } | bgp_proto MISSING LLADDR SELF ';' { BGP_CFG->missing_lladdr = MLL_SELF; } | bgp_proto MISSING LLADDR DROP ';' { BGP_CFG->missing_lladdr = MLL_DROP; } @@ -98,6 +98,7 @@ bgp_proto: | 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 bool ';' { BGP_CFG->ttl_security = $4; } ; CF_ADDTO(dynamic_attr, BGP_ORIGIN diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index 847ce26..95f7dcf 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -237,3 +237,34 @@ sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd) return rv; } + + +#ifndef IPV6 + +static int +sk_set_min_ttl4(sock *s, int ttl) +{ + if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) + { + if (errno == ENOPROTOOPT) + log(L_ERR "Kernel does not support IPv4 TTL security"); + else + log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); + + return -1; + } + + return 0; +} + +#else + +static int +sk_set_min_ttl6(sock *s, int ttl) +{ + log(L_ERR "IPv6 TTL security not supported"); + return -1; +} + +#endif + diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 9c10333..bb52280 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -309,3 +309,51 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) */ #endif + + +#ifndef IP_MINTTL +#define IP_MINTTL 21 +#endif + +#ifndef IPV6_MINHOPCOUNT +#define IPV6_MINHOPCOUNT 73 +#endif + + +#ifndef IPV6 + +static int +sk_set_min_ttl4(sock *s, int ttl) +{ + if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) + { + if (errno == ENOPROTOOPT) + log(L_ERR "Kernel does not support IPv4 TTL security"); + else + log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); + + return -1; + } + + return 0; +} + +#else + +static int +sk_set_min_ttl6(sock *s, int ttl) +{ + if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0) + { + if (errno == ENOPROTOOPT) + log(L_ERR "Kernel does not support IPv6 TTL security"); + else + log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); + + return -1; + } + + return 0; +} + +#endif diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index b6c1b86..815989f 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -805,7 +805,7 @@ bad: } /** - * sk_set_ttl - set TTL for given socket. + * sk_set_ttl - set transmit TTL for given socket. * @s: socket * @ttl: TTL value * @@ -828,6 +828,28 @@ sk_set_ttl(sock *s, int ttl) 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. diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 610d207..5547791 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -17,6 +17,7 @@ #include <signal.h> #include <pwd.h> #include <grp.h> +#include <sys/stat.h> #include "nest/bird.h" #include "lib/lists.h" |