-/* $OpenBSD: hello.c,v 1.52 2016/06/27 19:18:54 renato Exp $ */
+/* $OpenBSD: hello.c,v 1.53 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
/* multicast destination address */
switch (af) {
case AF_INET:
+ if (!(leconf->ipv4.flags & F_LDPD_AF_NO_GTSM))
+ flags |= GTSM_HELLO;
dst.v4 = global.mcast_addr_v4;
break;
case AF_INET6:
(trans_pref == DUAL_STACK_LDPOV6 && af == AF_INET6))))
nbr = nbr_new(lsr_id, af, ds_tlv, &trans_addr, scope_id);
+ /* dynamic LDPv4 GTSM negotiation as per RFC 6720 */
+ if (nbr) {
+ if (flags & GTSM_HELLO)
+ nbr->flags |= F_NBR_GTSM_NEGOTIATED;
+ else
+ nbr->flags &= ~F_NBR_GTSM_NEGOTIATED;
+ }
+
/* update neighbor's configuration sequence number */
if (nbr && (tlvs_rcvd & F_HELLO_TLV_RCVD_CONF)) {
if (conf_seqnum > nbr->conf_seqnum &&
-/* $OpenBSD: ldp.h,v 1.29 2016/05/23 19:14:03 renato Exp $ */
+/* $OpenBSD: ldp.h,v 1.30 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
#define TARGETED_HELLO 0x8000
#define REQUEST_TARG_HELLO 0x4000
+#define GTSM_HELLO 0x2000
struct hello_prms_opt4_tlv {
uint16_t type;
-.\" $OpenBSD: ldpd.8,v 1.15 2016/05/23 19:14:03 renato Exp $
+.\" $OpenBSD: ldpd.8,v 1.16 2016/07/01 23:14:31 renato Exp $
.\"
.\" Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: May 23 2016 $
+.Dd $Mdocdate: July 1 2016 $
.Dt LDPD 8
.Os
.Sh NAME
.Re
.Pp
.Rs
+.%A C. Pignataro
+.%A R. Asati
+.%D August 2012
+.%R RFC 6720
+.%T The Generalized TTL Security Mechanism (GTSM) for the Label Distribution Protocol (LDP)
+.Re
+.Pp
+.Rs
.%A R. Asati
.%A C. Pignataro
.%A K. Raza
-/* $OpenBSD: ldpd.c,v 1.54 2016/06/18 17:13:05 renato Exp $ */
+/* $OpenBSD: ldpd.c,v 1.55 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
{
int egress_label_changed = 0;
+ int update_sockets = 0;
if (af_conf->keepalive != xa->keepalive) {
af_conf->keepalive = xa->keepalive;
!(xa->flags & F_LDPD_AF_THELLO_ACCEPT))
ldpe_remove_dynamic_tnbrs(af);
+ if ((af_conf->flags & F_LDPD_AF_NO_GTSM) !=
+ (xa->flags & F_LDPD_AF_NO_GTSM)) {
+ if (af == AF_INET6)
+ /* need to set/unset IPV6_MINHOPCOUNT */
+ update_sockets = 1;
+ else if (ldpd_process == PROC_LDP_ENGINE)
+ /* for LDPv4 just resetting the neighbors is enough */
+ ldpe_reset_nbrs(af);
+ }
+
if ((af_conf->flags & F_LDPD_AF_EXPNULL) !=
(xa->flags & F_LDPD_AF_EXPNULL))
egress_label_changed = 1;
if (ldp_addrcmp(af, &af_conf->trans_addr, &xa->trans_addr)) {
af_conf->trans_addr = xa->trans_addr;
- if (ldpd_process == PROC_MAIN)
- imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af,
- 0, -1, NULL, 0);
+ update_sockets = 1;
}
+
+ if (ldpd_process == PROC_MAIN && update_sockets)
+ imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, 0, -1,
+ NULL, 0);
}
static void
}
/* update existing nbrps */
- if (nbrp->keepalive != xn->keepalive ||
+ if (nbrp->flags != xn->flags ||
+ nbrp->keepalive != xn->keepalive ||
+ nbrp->gtsm_enabled != xn->gtsm_enabled ||
+ nbrp->gtsm_hops != xn->gtsm_hops ||
nbrp->auth.method != xn->auth.method ||
strcmp(nbrp->auth.md5key, xn->auth.md5key) != 0)
nbrp_changed = 1;
-.\" $OpenBSD: ldpd.conf.5,v 1.29 2016/05/23 21:05:07 jmc Exp $
+.\" $OpenBSD: ldpd.conf.5,v 1.30 2016/07/01 23:14:31 renato Exp $
.\"
.\" Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: May 23 2016 $
+.Dd $Mdocdate: July 1 2016 $
.Dt LDPD.CONF 5
.Os
.Sh NAME
The default is
.Ic no .
.Pp
+.It Xo
+.Ic gtsm-enable
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic yes ,
+.Xr ldpd 8
+will use the GTSM procedures described in RFC 6720 (for the IPv4 address-family)
+and RFC 7552 (for the IPv6 address-family).
+.Pp
+Since GTSM is mandatory for LDPv6, the only effect of disabling GTSM for the
+IPv6 address-family is that
+.Xr ldpd 8
+will not check the incoming packets' Hop Limit.
+Outgoing packets will still be sent using a Hop Limit of 255 to guarantee
+interoperability.
+.Pp
+If GTSM is enabled, multi-hop neighbors should have either GTSM disabled
+individually or configured with an appropriate gtsm-hops distance.
+The default is
+.Ic yes .
+.Pp
.It Ic keepalive Ar seconds
Set the keepalive timeout in seconds.
The default value is 180; valid range is 3\-65535.
Set the keepalive timeout in seconds.
Inherited from the global configuration if not given.
The default value is 180; valid range is 3\-65535.
+.It Xo
+.Ic gtsm-enable
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+Override the inherited configuration and enable/disable GTSM for this neighbor.
+.It Ic gtsm-hops Ar hops
+Set the maximum number of hops the neighbor may be away.
+When GTSM is enabled for this neighbor, incoming packets are required to have
+a TTL/Hop Limit of 256 minus this value, ensuring they have not passed
+through more than the expected number of hops.
+The default value is 1; valid range is 1\-255.
.It Ic password Ar secret
Enable TCP MD5 signatures per RFC 5036.
.El
-/* $OpenBSD: ldpd.h,v 1.77 2016/06/13 23:01:37 renato Exp $ */
+/* $OpenBSD: ldpd.h,v 1.78 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
LIST_ENTRY(nbr_params) entry;
struct in_addr lsr_id;
uint16_t keepalive;
+ int gtsm_enabled;
+ uint8_t gtsm_hops;
struct {
enum auth_method method;
char md5key[TCP_MD5_KEY_LEN];
uint8_t flags;
};
#define F_NBRP_KEEPALIVE 0x01
+#define F_NBRP_GTSM 0x02
+#define F_NBRP_GTSM_HOPS 0x04
struct l2vpn_if {
LIST_ENTRY(l2vpn_if) entry;
#define F_LDPD_AF_ENABLED 0x0001
#define F_LDPD_AF_THELLO_ACCEPT 0x0002
#define F_LDPD_AF_EXPNULL 0x0004
+#define F_LDPD_AF_NO_GTSM 0x0008
struct ldpd_conf {
struct in_addr rtr_id;
void sock_set_recvbuf(int);
int sock_set_reuse(int, int);
int sock_set_bindany(int, int);
-int sock_set_ipv4_mcast_ttl(int, uint8_t);
int sock_set_ipv4_tos(int, int);
int sock_set_ipv4_recvif(int, int);
+int sock_set_ipv4_minttl(int, int);
+int sock_set_ipv4_ucast_ttl(int fd, int);
+int sock_set_ipv4_mcast_ttl(int, uint8_t);
int sock_set_ipv4_mcast(struct iface *);
int sock_set_ipv4_mcast_loop(int);
int sock_set_ipv6_dscp(int, int);
int sock_set_ipv6_pktinfo(int, int);
+int sock_set_ipv6_minhopcount(int, int);
+int sock_set_ipv6_ucast_hops(int, int);
+int sock_set_ipv6_mcast_hops(int, int);
int sock_set_ipv6_mcast(struct iface *);
int sock_set_ipv6_mcast_loop(int);
-/* $OpenBSD: ldpe.h,v 1.63 2016/06/27 19:06:33 renato Exp $ */
+/* $OpenBSD: ldpe.h,v 1.64 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
enum auth_method method;
char md5key[TCP_MD5_KEY_LEN];
} auth;
+ int flags;
};
+#define F_NBR_GTSM_NEGOTIATED 0x01
+
RB_HEAD(nbr_id_head, nbr);
RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare)
RB_HEAD(nbr_addr_head, nbr);
int nbr_pending_idtimer(struct nbr *);
int nbr_pending_connect(struct nbr *);
int nbr_establish_connection(struct nbr *);
+int nbr_gtsm_enabled(struct nbr *, struct nbr_params *);
+int nbr_gtsm_setup(int, int, struct nbr_params *);
+int nbr_gtsm_check(int, struct nbr *, struct nbr_params *);
struct nbr_params *nbr_params_new(struct in_addr);
struct nbr_params *nbr_params_find(struct ldpd_conf *, struct in_addr);
uint16_t nbr_get_keepalive(int, struct in_addr);
-/* $OpenBSD: neighbor.c,v 1.74 2016/06/13 23:01:37 renato Exp $ */
+/* $OpenBSD: neighbor.c,v 1.75 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
return (-1);
}
+ if (nbr_gtsm_check(nbr->fd, nbr, nbrp)) {
+ close(nbr->fd);
+ return (-1);
+ }
+
/*
* Send an extra hello to guarantee that the remote peer has formed
* an adjacency as well.
return (0);
}
+int
+nbr_gtsm_enabled(struct nbr *nbr, struct nbr_params *nbrp)
+{
+ /*
+ * RFC 6720 - Section 3:
+ * "This document allows for the implementation to provide an option to
+ * statically (e.g., via configuration) and/or dynamically override the
+ * default behavior and enable/disable GTSM on a per-peer basis".
+ */
+ if (nbrp && (nbrp->flags & F_NBRP_GTSM))
+ return (nbrp->gtsm_enabled);
+
+ if ((ldp_af_conf_get(leconf, nbr->af))->flags & F_LDPD_AF_NO_GTSM)
+ return (0);
+
+ /* By default, GTSM support has to be negotiated for LDPv4 */
+ if (nbr->af == AF_INET && !(nbr->flags & F_NBR_GTSM_NEGOTIATED))
+ return (0);
+
+ return (1);
+}
+
+int
+nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp)
+{
+ int ttl = 255;
+
+ if (nbrp && (nbrp->flags & F_NBRP_GTSM_HOPS))
+ ttl = 256 - nbrp->gtsm_hops;
+
+ switch (af) {
+ case AF_INET:
+ if (sock_set_ipv4_minttl(fd, ttl) == -1)
+ return (-1);
+ ttl = 255;
+ if (sock_set_ipv4_ucast_ttl(fd, ttl) == -1)
+ return (-1);
+ break;
+ case AF_INET6:
+ if (sock_set_ipv6_minhopcount(fd, ttl) == -1)
+ return (-1);
+ ttl = 255;
+ if (sock_set_ipv6_ucast_hops(fd, ttl) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("nbr_gtsm_setup: unknown af");
+ }
+
+ return (0);
+}
+
+int
+nbr_gtsm_check(int fd, struct nbr *nbr, struct nbr_params *nbrp)
+{
+ if (!nbr_gtsm_enabled(nbr, nbrp)) {
+ switch (nbr->af) {
+ case AF_INET:
+ sock_set_ipv4_ucast_ttl(fd, -1);
+ break;
+ case AF_INET6:
+ /*
+ * Send packets with a Hop Limit of 255 even when GSTM
+ * is disabled to guarantee interoperability.
+ */
+ sock_set_ipv6_ucast_hops(fd, 255);
+ break;
+ default:
+ fatalx("nbr_gtsm_check: unknown af");
+ break;
+ }
+ return (0);
+ }
+
+ if (nbr_gtsm_setup(fd, nbr->af, nbrp) == -1) {
+ log_warnx("%s: error enabling GTSM for lsr-id %s", __func__,
+ inet_ntoa(nbr->id));
+ return (-1);
+ }
+
+ return (0);
+}
+
static int
nbr_act_session_operational(struct nbr *nbr)
{
-/* $OpenBSD: packet.c,v 1.64 2016/06/18 17:31:32 renato Exp $ */
+/* $OpenBSD: packet.c,v 1.65 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
socklen_t len;
nbrp = nbr_params_find(leconf, nbr->id);
+ if (nbr_gtsm_check(fd, nbr, nbrp)) {
+ close(fd);
+ return;
+ }
+
if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
if (sysdep.no_pfkey || sysdep.no_md5sig) {
log_warnx("md5sig configured but not available");
-/* $OpenBSD: parse.y,v 1.56 2016/06/21 21:35:24 benno Exp $ */
+/* $OpenBSD: parse.y,v 1.57 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2015, 2016 Renato Westphal <renato@openbsd.org>
%token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE EXPNULL
%token LHELLOHOLDTIME LHELLOINTERVAL
%token THELLOHOLDTIME THELLOINTERVAL
-%token THELLOACCEPT AF IPV4 IPV6
+%token THELLOACCEPT AF IPV4 IPV6 GTSMENABLE GTSMHOPS
%token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP
%token NEIGHBOR PASSWORD
%token L2VPN TYPE VPLS PWTYPE MTU BRIDGE
YYERROR;
}
}
+ | GTSMENABLE yesno {
+ if ($2 == 0)
+ defs->afflags |= F_LDPD_AF_NO_GTSM;
+ }
| af_defaults
| iface_defaults
| tnbr_defaults
nbrp->auth.method = AUTH_MD5SIG;
free($2);
}
+ | GTSMENABLE yesno {
+ nbrp->flags |= F_NBRP_GTSM;
+ nbrp->gtsm_enabled = $2;
+ }
+ | GTSMHOPS NUMBER {
+ if ($2 < 1 || $2 > 255) {
+ yyerror("invalid number of hops %lld", $2);
+ YYERROR;
+ }
+ nbrp->gtsm_hops = $2;
+ nbrp->flags |= F_NBRP_GTSM_HOPS;
+ }
;
pw_defaults : STATUSTLV yesno {
{"ethernet-tagged", ETHERNETTAGGED},
{"explicit-null", EXPNULL},
{"fib-update", FIBUPDATE},
+ {"gtsm-enable", GTSMENABLE},
+ {"gtsm-hops", GTSMHOPS},
{"include", INCLUDE},
{"interface", INTERFACE},
{"ipv4", IPV4},
-/* $OpenBSD: printconf.c,v 1.25 2016/05/23 19:14:03 renato Exp $ */
+/* $OpenBSD: printconf.c,v 1.26 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
else
printf("\texplicit-null no\n");
+ if (af_conf->flags & F_LDPD_AF_NO_GTSM)
+ printf("\tgtsm-enable no\n");
+ else
+ printf("\tgtsm-enable yes\n");
+
printf("\tkeepalive %u\n", af_conf->keepalive);
printf("\ttransport-address %s\n", log_addr(af, &af_conf->trans_addr));
if (nbrp->flags & F_NBRP_KEEPALIVE)
printf("\tkeepalive %u\n", nbrp->keepalive);
+ if (nbrp->flags & F_NBRP_GTSM) {
+ if (nbrp->gtsm_enabled)
+ printf("\tgtsm-enable yes\n");
+ else
+ printf("\tgtsm-enable no\n");
+ }
+
+ if (nbrp->flags & F_NBRP_GTSM_HOPS)
+ printf("\tgtsm-hops %u\n", nbrp->gtsm_hops);
+
if (nbrp->auth.method == AUTH_MD5SIG)
printf("\tpassword XXXXXX\n");
-/* $OpenBSD: socket.c,v 1.7 2016/05/23 19:09:25 renato Exp $ */
+/* $OpenBSD: socket.c,v 1.8 2016/07/01 23:14:31 renato Exp $ */
/*
* Copyright (c) 2016 Renato Westphal <renato@openbsd.org>
return (-1);
}
}
+ if (type == LDP_SOCKET_SESSION) {
+ if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
break;
case AF_INET6:
if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
close(fd);
return (-1);
}
+ if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
+ close(fd);
+ return (-1);
+ }
+ if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
+ if (sock_set_ipv6_minhopcount(fd, 255) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
}
if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
return (-1);
}
}
+ if (type == LDP_SOCKET_SESSION) {
+ if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
break;
}
switch (type) {
}
int
-sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
+sock_set_ipv4_tos(int fd, int tos)
{
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
- (char *)&ttl, sizeof(ttl)) < 0) {
- log_warn("%s: error setting IP_MULTICAST_TTL to %d",
- __func__, ttl);
+ if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
+ log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
return (-1);
}
}
int
-sock_set_ipv4_tos(int fd, int tos)
+sock_set_ipv4_recvif(int fd, int enable)
{
- if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
- log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
+ if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
+ sizeof(enable)) < 0) {
+ log_warn("%s: error setting IP_RECVIF", __func__);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+sock_set_ipv4_minttl(int fd, int ttl)
+{
+ if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) {
+ log_warn("%s: error setting IP_MINTTL", __func__);
return (-1);
}
}
int
-sock_set_ipv4_recvif(int fd, int enable)
+sock_set_ipv4_ucast_ttl(int fd, int ttl)
{
- if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
- sizeof(enable)) < 0) {
- log_warn("%s: error setting IP_RECVIF", __func__);
+ if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
+ log_warn("%s: error setting IP_TTL", __func__);
return (-1);
}
+
+ return (0);
+}
+
+int
+sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
+{
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0) {
+ log_warn("%s: error setting IP_MULTICAST_TTL to %d",
+ __func__, ttl);
+ return (-1);
+ }
+
return (0);
}
return (0);
}
+int
+sock_set_ipv6_minhopcount(int fd, int hoplimit)
+{
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
+ &hoplimit, sizeof(hoplimit)) < 0) {
+ log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+sock_set_ipv6_ucast_hops(int fd, int hoplimit)
+{
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ &hoplimit, sizeof(hoplimit)) < 0) {
+ log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+sock_set_ipv6_mcast_hops(int fd, int hoplimit)
+{
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &hoplimit, sizeof(hoplimit)) < 0) {
+ log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
int
sock_set_ipv6_mcast(struct iface *iface)
{