From a39b165e45fbfea053fd0237e0d5a3ebdcf40f78 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 1 Nov 2008 16:58:40 +0100 Subject: [PATCH] Multihop BGP was completely broken, because listening socket has always ttl 1. --- lib/socket.h | 1 + proto/bgp/bgp.c | 14 +++++------ sysdep/unix/io.c | 63 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 58 insertions(+), 20 deletions(-) diff --git a/lib/socket.h b/lib/socket.h index 4aa521db..5fe91931 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -48,6 +48,7 @@ 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_md5_auth(sock *s, ip_addr a, char *passwd); /* Add or remove security associations for given passive socket */ static inline int diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index a34545bb..29d2e09f 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -298,11 +298,7 @@ static void bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s) { s->data = conn; - s->ttl = p->cf->multihop ? : 1; - s->rbsize = BGP_RX_BUFFER_SIZE; - s->tbsize = BGP_TX_BUFFER_SIZE; s->err_hook = bgp_sock_err; - s->tos = IP_PREC_INTERNET_CONTROL; conn->sk = s; } @@ -330,11 +326,15 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->saddr = p->local_addr; s->daddr = p->cf->remote_ip; s->dport = BGP_PORT; + s->ttl = p->cf->multihop ? : 1; + s->rbsize = BGP_RX_BUFFER_SIZE; + s->tbsize = BGP_TX_BUFFER_SIZE; + s->tos = IP_PREC_INTERNET_CONTROL; + s->password = p->cf->password; + s->tx_hook = bgp_connected; BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr); bgp_setup_conn(p, conn); bgp_setup_sk(p, conn, s); - s->tx_hook = bgp_connected; - s->password = p->cf->password; conn->state = BS_CONNECT; if (sk_open(s)) { @@ -399,6 +399,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) } bgp_setup_conn(p, &p->incoming_conn); bgp_setup_sk(p, &p->incoming_conn, sk); + sk_set_ttl(sk, p->cf->multihop ? : 1); bgp_send_open(&p->incoming_conn); return 0; } @@ -420,7 +421,6 @@ bgp_setup_listen_sk(void) s->type = SK_TCP_PASSIVE; s->sport = BGP_PORT; s->tos = IP_PREC_INTERNET_CONTROL; - s->ttl = 1; s->rbsize = BGP_RX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE; s->rx_hook = bgp_incoming_connection; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 8cec2cdd..e67ed80f 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -610,6 +610,25 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check) #endif +static char * +sk_set_ttl_int(sock *s) +{ + int one = 1; +#ifdef IPV6 + if (s->type != SK_UDP_MC && s->type != SK_IP_MC && + setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) + return "IPV6_UNICAST_HOPS"; +#else + if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) + return "IP_TTL"; +#ifdef CONFIG_UNIX_DONTROUTE + if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) + return "SO_DONTROUTE"; +#endif +#endif + return NULL; +} + #define ERR(x) do { err = x; goto bad; } while(0) #define WARN(x) log(L_WARN "sk_setup: %s: %m", x) @@ -617,32 +636,50 @@ static char * sk_setup(sock *s) { int fd = s->fd; - int one = 1; char *err; if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) ERR("fcntl(O_NONBLOCK)"); if (s->type == SK_UNIX) return NULL; -#ifdef IPV6 - if (s->ttl >= 0 && s->type != SK_UDP_MC && s->type != SK_IP_MC && - setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) - ERR("IPV6_UNICAST_HOPS"); -#else +#ifndef IPV6 if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) WARN("IP_TOS"); - if (s->ttl >= 0 && setsockopt(fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) - ERR("IP_TTL"); -#ifdef CONFIG_UNIX_DONTROUTE - if (s->ttl == 1 && setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) - ERR("SO_DONTROUTE"); -#endif #endif - err = NULL; + + if (s->ttl >= 0) + err = sk_set_ttl_int(s); + else + err = NULL; + bad: return err; } +/** + * sk_set_ttl - set TTL for given socket. + * @s: socket + * @ttl: TTL value + * + * Set TTL for already opened connections when TTL was not set before. + * Useful for accepted connections when different ones should have + * different TTL. + * + * Result: 0 for success, -1 for an error. + */ + +int +sk_set_ttl(sock *s, int ttl) +{ + char *err; + + s->ttl = ttl; + if (err = sk_set_ttl_int(s)) + log(L_ERR "sk_set_ttl: %s: %m", err); + + return (err ? -1 : 0); +} + /* FIXME: check portability */