Module Name: src Committed By: kefren Date: Mon Nov 12 18:39:01 UTC 2012
Modified Files: src/usr.sbin/ldpd: Makefile conffile.c fsm.c ldp.h ldp_peer.c ldp_peer.h ldpd.8 main.c notifications.h socketops.c socketops.h tlv.h tlv_stack.c Log Message: * add initial IPv6 support - still incomplete at this moment, but it sends out there IPv6 hellos. Interoperability not yet tested. * sync man page with reality To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/ldpd/Makefile \ src/usr.sbin/ldpd/conffile.c src/usr.sbin/ldpd/ldp.h \ src/usr.sbin/ldpd/ldp_peer.c cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/ldpd/fsm.c src/usr.sbin/ldpd/ldpd.8 cvs rdiff -u -r1.1 -r1.2 src/usr.sbin/ldpd/ldp_peer.h \ src/usr.sbin/ldpd/notifications.h src/usr.sbin/ldpd/tlv.h cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/ldpd/main.c cvs rdiff -u -r1.11 -r1.12 src/usr.sbin/ldpd/socketops.c cvs rdiff -u -r1.2 -r1.3 src/usr.sbin/ldpd/socketops.h cvs rdiff -u -r1.4 -r1.5 src/usr.sbin/ldpd/tlv_stack.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/ldpd/Makefile diff -u src/usr.sbin/ldpd/Makefile:1.3 src/usr.sbin/ldpd/Makefile:1.4 --- src/usr.sbin/ldpd/Makefile:1.3 Thu Dec 30 11:29:21 2010 +++ src/usr.sbin/ldpd/Makefile Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.3 2010/12/30 11:29:21 kefren Exp $ +# $NetBSD: Makefile,v 1.4 2012/11/12 18:39:00 kefren Exp $ .include <bsd.own.mk> @@ -22,4 +22,8 @@ SRCS= conffile.c \ LDADD+= -lcrypt +.if (${USE_INET6} != "no") +CPPFLAGS+=-DINET6 +.endif + .include <bsd.prog.mk> Index: src/usr.sbin/ldpd/conffile.c diff -u src/usr.sbin/ldpd/conffile.c:1.3 src/usr.sbin/ldpd/conffile.c:1.4 --- src/usr.sbin/ldpd/conffile.c:1.3 Tue Jun 14 11:28:51 2011 +++ src/usr.sbin/ldpd/conffile.c Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: conffile.c,v 1.3 2011/06/14 11:28:51 kefren Exp $ */ +/* $NetBSD: conffile.c,v 1.4 2012/11/12 18:39:00 kefren Exp $ */ /* * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -45,7 +45,7 @@ #define LINEMAXSIZE 1024 extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port, - min_label, max_label, no_default_route; + min_label, max_label, no_default_route, loop_detection; int confh; struct in_addr conf_ldp_id; @@ -62,6 +62,7 @@ static int Fldpid(char*); static int Fneighbour(char*); static int Gneighbour(struct conf_neighbour *, char *); static int Fnodefault(char*); +static int Floopdetection(char*); struct conf_func { char com[64]; @@ -79,6 +80,7 @@ struct conf_func main_commands[] = { { "neighbor", Fneighbour }, { "neighbour", Fneighbour }, { "no-default-route", Fnodefault }, + { "loop-detection", Floopdetection }, { "", NULL }, }; @@ -312,3 +314,13 @@ Fnodefault(char *line) no_default_route = nd; return 0; } + +int +Floopdetection(char *line) +{ + int loopd = atoi(line); + if (loopd < 0) + return E_CONF_PARAM; + loop_detection = loopd; + return 0; +} Index: src/usr.sbin/ldpd/ldp.h diff -u src/usr.sbin/ldpd/ldp.h:1.3 src/usr.sbin/ldpd/ldp.h:1.4 --- src/usr.sbin/ldpd/ldp.h:1.3 Thu Jun 16 14:48:30 2011 +++ src/usr.sbin/ldpd/ldp.h Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ldp.h,v 1.3 2011/06/16 14:48:30 kefren Exp $ */ +/* $NetBSD: ldp.h,v 1.4 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -36,10 +36,11 @@ #include <netinet/in.h> #define ALL_ROUTERS "224.0.0.2" +#define ALL_ROUTERS6 "FF02::2" #define LDP_PORT 646 #define LDP_COMMAND_PORT 2626 -#define LDPD_VER "0.3.0" +#define LDPD_VER "0.4.0" #define CONFFILE "/etc/ldpd.conf" Index: src/usr.sbin/ldpd/ldp_peer.c diff -u src/usr.sbin/ldpd/ldp_peer.c:1.3 src/usr.sbin/ldpd/ldp_peer.c:1.4 --- src/usr.sbin/ldpd/ldp_peer.c:1.3 Thu Dec 30 11:29:21 2010 +++ src/usr.sbin/ldpd/ldp_peer.c Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ldp_peer.c,v 1.3 2010/12/30 11:29:21 kefren Exp $ */ +/* $NetBSD: ldp_peer.c,v 1.4 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -68,7 +68,8 @@ ldp_peer_init(void) */ struct ldp_peer * ldp_peer_new(struct in_addr * ldp_id, struct in_addr * a, - struct in_addr * tradd, uint16_t holdtime, int soc) + struct in_addr * tradd, struct in6_addr * tradd6, + uint16_t holdtime, int soc) { struct ldp_peer *p; int s = soc; Index: src/usr.sbin/ldpd/fsm.c diff -u src/usr.sbin/ldpd/fsm.c:1.5 src/usr.sbin/ldpd/fsm.c:1.6 --- src/usr.sbin/ldpd/fsm.c:1.5 Thu Jun 16 14:48:30 2011 +++ src/usr.sbin/ldpd/fsm.c Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: fsm.c,v 1.5 2011/06/16 14:48:30 kefren Exp $ */ +/* $NetBSD: fsm.c,v 1.6 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -56,6 +56,7 @@ run_ldp_hello(struct ldp_pdu * pduid, st { struct ldp_peer *peer = NULL; struct in_addr peer_addr; + struct in6_addr peer_addr6; struct transport_address_tlv *trtlv; struct hello_info *hi; @@ -113,16 +114,20 @@ run_ldp_hello(struct ldp_pdu * pduid, st if (trtlv->type == TLV_IPV4_TRANSPORT) memcpy(&peer_addr, &trtlv->address, sizeof(struct in_addr)); + else if (trtlv->type == TLV_IPV6_TRANSPORT) + memcpy(&peer_addr6, &trtlv->address, + sizeof(struct in6_addr)); } else trtlv = NULL; /* - * RFC says: If A1 > A2, LSR1 plays the active role; + * RFC 5036 2.5.2: If A1 > A2, LSR1 plays the active role; * otherwise it is passive. */ if (ntohl(peer_addr.s_addr) < ntohl(ladd->s_addr)) { -#define TRADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL +#define TR_INET4_ADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL +#define TR_INET6_ADDR NULL peer = ldp_peer_new(&pduid->ldp_id, padd, - TRADDR, ht->ch.holdtime, 0); + TR_INET4_ADDR, TR_INET6_ADDR, ht->ch.holdtime, 0); if (!peer) return; if (peer && peer->state == LDP_PEER_CONNECTED) Index: src/usr.sbin/ldpd/ldpd.8 diff -u src/usr.sbin/ldpd/ldpd.8:1.5 src/usr.sbin/ldpd/ldpd.8:1.6 --- src/usr.sbin/ldpd/ldpd.8:1.5 Thu Jul 7 05:20:16 2011 +++ src/usr.sbin/ldpd/ldpd.8 Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -.\" $NetBSD: ldpd.8,v 1.5 2011/07/07 05:20:16 kefren Exp $ +.\" $NetBSD: ldpd.8,v 1.6 2012/11/12 18:39:00 kefren Exp $ .\" .\" Copyright (c) 2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -38,35 +38,40 @@ .Sh DESCRIPTION .Nm is a utility used to automatically distribute labels between two MPLS LSRs -almost conforming to RFC3036. -Right now it is in BETA stage and many features -are not implemented or may not work. -As a security measure you SHOULD filter the LDP well-known (646) +almost conforming to RFC5036. +Right now some features requested by RFC5036 are not fully implemented. +For more information please consult the +.Sx BUGS +section. As a security measure you SHOULD filter the LDP well-known (646) TCP and UDP ports using your favourite packet filter before starting .Nm . -Also this is the current measure used to filter neighbours. -You should see some logs reported via +This is the current way used to filter neighbours and to protect the +system of external attacks like route injections. +.Pp +.Nm +logs information using the .Xr syslog 3 interface. -.Pp You can increase the log verbosity using the .Fl W and .Fl D flags. -Also you can telnet to the control port (default: 2626) and use -this interface in order to get informations about protocol, neighbours -etc. but also to set runtime parameters. -The required password is the same as the root password. +.Pp +Administrators can use +.Xr telnet 1 +to connect to the control port (default: 2626) and use +this interface in order to get informations about protocol status, +neighbours et cetera but also to set runtime parameters. +The password required for connecting is the same as the root password. .Pp .Nm computes existing routes and tries to match them on MPLS labels announced by other LDP peers. -This means that -.Dq normal +This means that usual IP routes will be changed into tagged routes, and MPLS routing table will be populated. -It will also announce its mappings to its peers. +Any change in MPLS topology will also be announced to LDP neighbors. .Nm will listen on a route socket and compute the necessary changes in order to change untagged routes into tagged routes. @@ -86,6 +91,8 @@ for configuration file format. Enable debug mode. .It Fl d Don't use route interception code. +.Nm +will not make any changes to routing table if started with this option. .It Fl f Run in foreground. Use STDOUT for warning and debug messages. @@ -99,8 +106,8 @@ Enable output of warning messages. .Sh SEE ALSO .Rs .%R RFC -.%N 3036 -.%D January 2001 +.%N 5036 +.%D October 2007 .%T LDP Specification .Re .Rs Index: src/usr.sbin/ldpd/ldp_peer.h diff -u src/usr.sbin/ldpd/ldp_peer.h:1.1 src/usr.sbin/ldpd/ldp_peer.h:1.2 --- src/usr.sbin/ldpd/ldp_peer.h:1.1 Wed Dec 8 07:20:14 2010 +++ src/usr.sbin/ldpd/ldp_peer.h Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ldp_peer.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */ +/* $NetBSD: ldp_peer.h,v 1.2 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -86,7 +86,7 @@ struct peer_map { void ldp_peer_init(void); struct ldp_peer * ldp_peer_new(struct in_addr *, struct in_addr *, - struct in_addr *, uint16_t, int); + struct in_addr *, struct in6_addr *, uint16_t, int); void ldp_peer_holddown(struct ldp_peer *); void ldp_peer_delete(struct ldp_peer *); struct ldp_peer * get_ldp_peer(struct in_addr *); Index: src/usr.sbin/ldpd/notifications.h diff -u src/usr.sbin/ldpd/notifications.h:1.1 src/usr.sbin/ldpd/notifications.h:1.2 --- src/usr.sbin/ldpd/notifications.h:1.1 Wed Dec 8 07:20:15 2010 +++ src/usr.sbin/ldpd/notifications.h Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: notifications.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */ +/* $NetBSD: notifications.h,v 1.2 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #ifndef _NOTIFICATIONS_H_ #define _NOTIFICATIONS_H_ -/* Notifications codes RFC3036 2.9 */ +/* Notifications codes from RFC5036 3.9 - Status code summary */ #define NOTIF_SUCCESS 0x00000000 #define NOTIF_BAD_LDP_ID 0x00000001 #define NOTIF_BAD_LDP_VER 0x00000002 Index: src/usr.sbin/ldpd/tlv.h diff -u src/usr.sbin/ldpd/tlv.h:1.1 src/usr.sbin/ldpd/tlv.h:1.2 --- src/usr.sbin/ldpd/tlv.h:1.1 Wed Dec 8 07:20:15 2010 +++ src/usr.sbin/ldpd/tlv.h Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: tlv.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */ +/* $NetBSD: tlv.h,v 1.2 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -91,7 +91,10 @@ struct hello_tlv { struct transport_address_tlv { uint16_t type; uint16_t length; - struct in_addr address; + union { + struct in_addr ip4addr; + struct in6_addr ip6addr; + } address; } __packed; Index: src/usr.sbin/ldpd/main.c diff -u src/usr.sbin/ldpd/main.c:1.6 src/usr.sbin/ldpd/main.c:1.7 --- src/usr.sbin/ldpd/main.c:1.6 Sat Jul 2 18:17:12 2011 +++ src/usr.sbin/ldpd/main.c Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.6 2011/07/02 18:17:12 kefren Exp $ */ +/* $NetBSD: main.c,v 1.7 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -139,7 +139,7 @@ main(int argc, char *argv[]) fatalp("Cannot create command socket\n"); return EXIT_FAILURE; } - if (create_hello_socket() < 1) { + if (create_hello_sockets() != 0) { fatalp("Cannot create hello socket\n"); return EXIT_FAILURE; } Index: src/usr.sbin/ldpd/socketops.c diff -u src/usr.sbin/ldpd/socketops.c:1.11 src/usr.sbin/ldpd/socketops.c:1.12 --- src/usr.sbin/ldpd/socketops.c:1.11 Wed Aug 31 13:32:38 2011 +++ src/usr.sbin/ldpd/socketops.c Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: socketops.c,v 1.11 2011/08/31 13:32:38 joerg Exp $ */ +/* $NetBSD: socketops.c,v 1.12 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -60,12 +60,15 @@ #include "ldp_errors.h" #include "socketops.h" -int ls; /* TCP listening socket on port 646 */ -int route_socket; /* used to see when a route is added/deleted */ -int hello_socket; /* hello multicast listener - transmitter */ -int command_socket; /* Listening socket for interface command */ -int current_msg_id = 0x233; -int command_port = LDP_COMMAND_PORT; +int ls; /* TCP listening socket on port 646 */ +int route_socket; /* used to see when a route is added/deleted */ +int hello_socket; /* hello RX/TX multicast sockets */ +#ifdef INET6 +int hello6_socket; /* same as above */ +#endif +int command_socket; /* Listening socket for interface command */ +int current_msg_id = 0x233; +int command_port = LDP_COMMAND_PORT; extern int replay_index; extern struct rt_msg replay_rt[REPLAY_MAX]; extern struct com_sock csockets[MAX_COMMAND_SOCKETS]; @@ -74,70 +77,141 @@ int ldp_hello_time = LDP_HELLO_TIME; int ldp_keepalive_time = LDP_KEEPALIVE_TIME; int ldp_holddown_time = LDP_HOLDTIME; int no_default_route = 1; +int loop_detection = 0; void recv_pdu(int); void send_hello_alarm(int); __dead static void bail_out(int); +static int bind_socket(int s, uint8_t stype); +static int set_mcast_ttl(int, int); +static int set_tos(int); +static int socket_reuse_port(int); static int get_local_addr(struct sockaddr_dl *, struct in_addr *); int -create_hello_socket() +create_hello_sockets() { struct ip_mreq mcast_addr; - int s = socket(PF_INET, SOCK_DGRAM, 17); + int s; +#ifdef INET6 + struct ipv6_mreq mcast_addr6; + int s6; +#endif + s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) return s; +#ifdef INET6 + s6 = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s6 < 0) { + close(s); + return s6; + } +#endif /* - * RFC3036 specifies we should listen to all subnet routers multicast + * RFC5036 specifies we should listen to all subnet routers multicast * group */ - mcast_addr.imr_multiaddr.s_addr = inet_addr(ALL_ROUTERS); + assert(inet_pton(AF_INET, ALL_ROUTERS, &mcast_addr.imr_multiaddr) == 1); mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY); - socket_reuse_port(s); +#ifdef INET6 + assert(inet_pton(AF_INET6, ALL_ROUTERS6, + &mcast_addr6.ipv6mr_multiaddr) == 1); + /* + * XXXXX: kefren. This should be 0, else I should create a socket + * for every interface. Need to investigate why is not working + * as documented in ip6(4) + */ + mcast_addr6.ipv6mr_interface = 1; +#endif + + if (socket_reuse_port(s) < 0) + goto chs_error; +#ifdef INET6 + if (socket_reuse_port(s6) < 0) + goto chs_error; +#endif + /* Bind it to port 646 on specific address */ - if (bind_socket(s, htonl(INADDR_ANY)) == -1) { - warnp("Cannot bind hello socket\n"); - close(s); - return -1; + if (bind_socket(s, 4) == -1) { + warnp("Cannot bind INET hello socket\n"); + goto chs_error; + } +#ifdef INET6 + if (bind_socket(s6, 6) == -1) { + fatalp("Cannot bind INET6 hello socket\n"); + goto chs_error; } +#endif + /* We don't need to receive back our messages */ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &(uint8_t){0}, sizeof(uint8_t)) == -1) { - fatalp("setsockopt: %s", strerror(errno)); - close(s); - return -1; + fatalp("INET setsockopt IP_MCAST_LOOP: %s\n", strerror(errno)); + goto chs_error; + } +#ifdef INET6 + if (setsockopt(s6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &(uint32_t){0}, + sizeof(uint32_t)) == -1) { + fatalp("INET6 setsocketopt IP_MCAST_LOOP: %s\n", + strerror(errno)); + goto chs_error; } +#endif + /* Finally join the group */ if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mcast_addr, sizeof(mcast_addr)) == -1) { - fatalp("setsockopt: %s", strerror(errno)); - close(s); - return -1; + fatalp("setsockopt ADD_MEMBER: %s\n", strerror(errno)); + goto chs_error; } - /* TTL:1, TOS: 0xc0 */ - if (set_mcast_ttl(s) == -1) { - close(s); - return -1; +#ifdef INET6 + if (setsockopt(s6, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcast_addr6, + sizeof(mcast_addr6)) == -1) { + fatalp("INET6 setsockopt JOIN: %s\n", strerror(errno)); + goto chs_error; } +#endif + /* TTL:1, TOS: 0xc0 */ + if (set_mcast_ttl(s, 4) == -1) + goto chs_error; +#ifdef INET6 + if (set_mcast_ttl(s6, 6) == -1) + goto chs_error; +#endif if (set_tos(s) == -1) { fatalp("set_tos: %s", strerror(errno)); - close(s); - return -1; + goto chs_error; } + + /* we need to get the input interface for message processing */ if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &(uint32_t){1}, sizeof(uint32_t)) == -1) { fatalp("Cannot set IP_RECVIF\n"); - close(s); - return -1; + goto chs_error; } +#ifdef INET6 + if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &(uint32_t){1}, sizeof(uint32_t)) == -1) + goto chs_error; +#endif + hello_socket = s; - return hello_socket; +#ifdef INET6 + hello6_socket = s6; +#endif + + return 0; +chs_error: + close(s); +#ifdef INET6 + close(s6); +#endif + return -1; } /* Sets the TTL to 1 as we don't want to transmit outside this subnet */ -int +int set_ttl(int s) { int ret; @@ -148,18 +222,21 @@ set_ttl(int s) } /* Sets multicast TTL to 1 */ -int -set_mcast_ttl(int s) +static int +set_mcast_ttl(int s, int stype) { int ret; - if ((ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &(int){1}, + + assert(stype == 4 || stype == 6); + if ((ret = setsockopt(s, stype == 4 ? IPPROTO_IP : IPPROTO_IPV6, + stype == 4 ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS, &(int){1}, sizeof(int))) == -1) fatalp("set_mcast_ttl: %s", strerror(errno)); return ret; } /* Sets TOS to 0xc0 aka IP Precedence 6 */ -int +static int set_tos(int s) { int ret; @@ -169,10 +246,10 @@ set_tos(int s) return ret; } -int +static int socket_reuse_port(int s) { - int ret; + int ret; if ((ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int))) == -1) fatalp("socket_reuse_port: %s", strerror(errno)); @@ -180,24 +257,38 @@ socket_reuse_port(int s) } /* binds an UDP socket */ -int -bind_socket(int s, uint32_t addr) +static int +bind_socket(int s, uint8_t stype) { - struct sockaddr_in sa; + struct sockaddr sa; - sa.sin_len = sizeof(sa); - sa.sin_family = AF_INET; - sa.sin_port = htons(LDP_PORT); - sa.sin_addr.s_addr = addr; - if (bind(s, (struct sockaddr *) (&sa), sizeof(sa))) { - fatalp("bind_socket: %s", strerror(errno)); + assert (stype == 4 || stype == 6); + + if (stype == 4) { + struct sockaddr_in *sa_inet = (struct sockaddr_in *)(&sa); + sa_inet->sin_len = sizeof(*sa_inet); + sa_inet->sin_family = AF_INET; + sa_inet->sin_addr.s_addr = INADDR_ANY; + sa_inet->sin_port = htons(LDP_PORT); + } +#ifdef INET6 + else if (stype == 6) { + struct sockaddr_in6 *sa_inet6 = (struct sockaddr_in6 *)(&sa); + sa_inet6->sin6_len = sizeof(*sa_inet6); + sa_inet6->sin6_family = AF_INET6; + sa_inet6->sin6_addr = in6addr_any; + sa_inet6->sin6_port = htons(LDP_PORT); + } +#endif + if (bind(s, &sa, sa.sa_len)) { + fatalp("bind_socket: %s\n", strerror(errno)); return -1; } return 0; } /* Create / bind the TCP socket */ -int +int create_listening_socket(void) { struct sockaddr_in sa; @@ -208,7 +299,7 @@ create_listening_socket(void) sa.sin_port = htons(LDP_PORT); sa.sin_addr.s_addr = htonl(INADDR_ANY); - s = socket(PF_INET, SOCK_STREAM, 6); + s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) return s; if (bind(s, (struct sockaddr *) & sa, sizeof(sa))) { @@ -242,20 +333,27 @@ send_hello(void) struct transport_address_tlv *trtlv; void *v; struct sockaddr_in sadest; /* Destination ALL_ROUTERS */ - int sb = 0; /* sent bytes */ + ssize_t sb = 0; /* sent bytes */ struct ifaddrs *ifa, *ifb; struct sockaddr_in *if_sa; +#ifdef INET6 + struct sockaddr_in6 sadest6; + struct sockaddr_in6 *if_sa6; +#endif char lastifname[20]; -#define HELLO_MSG_SIZE (sizeof(struct ldp_pdu) + /* PDU */ \ +#define BASIC_HELLO_MSG_SIZE (sizeof(struct ldp_pdu) + /* PDU */ \ TLV_TYPE_LENGTH + MSGID_SIZE + /* Hello TLV */ \ /* Common Hello TLV */ \ - sizeof(struct common_hello_tlv) + \ - /* IPv4 Transport Address */ \ - sizeof(struct transport_address_tlv)) + sizeof(struct common_hello_tlv)) +#define GENERAL_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + \ + /* Transport Address */ \ + sizeof(struct transport_address_tlv) +#define IPV4_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 4 + sizeof(struct in_addr) +#define IPV6_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 4 + sizeof(struct in6_addr) - if ((v = calloc(1, HELLO_MSG_SIZE)) == NULL) { - fatalp("malloc problem in send_hello()\n"); + if ((v = calloc(1, GENERAL_HELLO_MSG_SIZE)) == NULL) { + fatalp("alloc problem in send_hello()\n"); return; } @@ -266,17 +364,18 @@ send_hello(void) /* Prepare PDU envelope */ spdu->version = htons(LDP_VERSION); - spdu->length = htons(HELLO_MSG_SIZE - PDU_VER_LENGTH); + spdu->length = htons(IPV4_HELLO_MSG_SIZE - PDU_VER_LENGTH); inet_aton(LDP_ID, &spdu->ldp_id); /* Prepare Hello TLV */ t->type = htons(LDP_HELLO); t->length = htons(MSGID_SIZE + sizeof(struct common_hello_tlv) + - sizeof(struct transport_address_tlv)); + IPV4_HELLO_MSG_SIZE - BASIC_HELLO_MSG_SIZE); /* + * kefren: * I used ID 0 instead of htonl(get_message_id()) because I've - * seen hellos from a cisco router doing the same thing + * seen hellos from Cisco routers doing the same thing */ t->messageid = 0; @@ -287,7 +386,7 @@ send_hello(void) cht->res = 0; /* - * Prepare Transport Address TLV RFC3036 says: "If this optional TLV + * Prepare Transport Address TLV RFC5036 says: "If this optional TLV * is not present the IPv4 source address for the UDP packet carrying * the Hello should be used." But we send it because everybody seems * to do so @@ -309,6 +408,7 @@ send_hello(void) } lastifname[0] = '\0'; + /* Loop all interfaces in order to send IPv4 hellos */ for (ifb = ifa; ifb; ifb = ifb->ifa_next) { if_sa = (struct sockaddr_in *) ifb->ifa_addr; if (if_sa->sin_family != AF_INET) @@ -316,7 +416,8 @@ send_hello(void) if (ntohl(if_sa->sin_addr.s_addr) >> 24 == IN_LOOPBACKNET || ntohl(if_sa->sin_addr.s_addr) >> 24 == 0) continue; - /* Send only once per interface, using master address */ + + /* Send only once per interface, using primary address */ if (strcmp(ifb->ifa_name, lastifname) == 0) continue; debugp("Sending hello on %s\n", ifb->ifa_name); @@ -325,22 +426,80 @@ send_hello(void) warnp("setsockopt failed: %s\n", strerror(errno)); continue; } - trtlv->address.s_addr = if_sa->sin_addr.s_addr; + trtlv->address.ip4addr.s_addr = if_sa->sin_addr.s_addr; strlcpy(lastifname, ifb->ifa_name, sizeof(lastifname)); /* Send to the wire */ - sb = sendto(hello_socket, v, HELLO_MSG_SIZE, + sb = sendto(hello_socket, v, IPV4_HELLO_MSG_SIZE, 0, (struct sockaddr *) & sadest, sizeof(sadest)); - if (sb < (int)HELLO_MSG_SIZE) + if (sb < (ssize_t)(IPV4_HELLO_MSG_SIZE)) fatalp("send: %s", strerror(errno)); else - debugp("Send %d bytes (PDU: %d, Hello TLV: %d, CH: %d)\n", - sb, (int) (sizeof(struct ldp_pdu) - PDU_VER_LENGTH), - (int) (TLV_TYPE_LENGTH + MSGID_SIZE), - (int) (sizeof(struct common_hello_tlv))); + debugp("Sent (IP4) %lu bytes on %s" + "(PDU: %d, Hello TLV: %d, CH: %d, TR: %d)\n", + sb, ifb->ifa_name, + ntohs(spdu->length), ntohs(t->length), + ntohs(cht->length), ntohs(trtlv->length)); + } +#ifdef INET6 + /* Let's do the same thing for IPv6 */ + lastifname[0]='\0'; + + /* Adjust lengths */ + spdu->length = htons(IPV6_HELLO_MSG_SIZE - PDU_VER_LENGTH); + t->length = htons(MSGID_SIZE + + sizeof(struct common_hello_tlv) + + IPV6_HELLO_MSG_SIZE - BASIC_HELLO_MSG_SIZE); + trtlv->length = htons(sizeof(struct in6_addr)); + trtlv->type = htons(TLV_IPV6_TRANSPORT); + + /* Prepare destination sockaddr */ + memset(&sadest6, 0, sizeof(sadest6)); + sadest6.sin6_len = sizeof(sadest6); + sadest6.sin6_family = AF_INET6; + sadest6.sin6_port = htons(LDP_PORT); + assert(inet_pton(AF_INET6, ALL_ROUTERS6, &sadest6.sin6_addr) == 1); + + for (ifb = ifa; ifb; ifb = ifb->ifa_next) { + unsigned int if_index; + if_sa6 = (struct sockaddr_in6 *) ifb->ifa_addr; + if (if_sa6->sin6_family != AF_INET6) + continue; + if (IN6_IS_ADDR_LOOPBACK(&if_sa6->sin6_addr)) + continue; + + /* Send only once per interface, using primary address */ + if (strcmp(ifb->ifa_name, lastifname) == 0) + continue; + if_index = if_nametoindex(ifb->ifa_name); + if (if_index == 0) + continue; + if (setsockopt(hello6_socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &if_index, sizeof(int)) == -1) { + warnp("setsockopt6 failed in sendhello(): %s\n", + strerror(errno)); + continue; + } + memcpy(&trtlv->address.ip6addr, &if_sa6->sin6_addr, + sizeof(struct in6_addr)); + + strlcpy(lastifname, ifb->ifa_name, sizeof(lastifname)); + + /* Put it on the wire */ + sb = sendto(hello6_socket, v, IPV6_HELLO_MSG_SIZE, + 0, (struct sockaddr *)&sadest6, sizeof(sadest6)); + if (sb < (ssize_t)(IPV6_HELLO_MSG_SIZE)) + fatalp("send6 on %s: %s", ifb->ifa_name, strerror(errno)); + else + debugp("Sent (IPv6) %lu bytes on %s" + "(PDU: %d, Hello TLV: %d, CH: %d TR: %d)\n", + sb, ifb->ifa_name, + htons(spdu->length), htons(t->length), + htons(cht->length), htons(trtlv->length)); } +#endif freeifaddrs(ifa); free(v); } @@ -714,8 +873,8 @@ new_peer_connection() close(s); return; } - /* XXX: sa.sin_addr ain't peer LDP ID ... */ - ldp_peer_new(&sa.sin_addr, &sa.sin_addr, NULL, ldp_holddown_time, s); + /* XXX: sa.sin_addr is not peer LDP ID ... */ + ldp_peer_new(&sa.sin_addr, &sa.sin_addr, NULL, NULL, ldp_holddown_time, s); } @@ -940,7 +1099,7 @@ recv_session_pdu(struct ldp_peer * p) break; case LDP_LABEL_ABORT: /* XXX: For now I pretend I can process everything - * RFC 3036, Section 3.5.9.1 + * RFC 5036, Section 3.5.9.1 * If an LSR receives a Label Abort Request Message after it * has responded to the Label Request in question with a Label * Mapping message or a Notification message, it ignores the Index: src/usr.sbin/ldpd/socketops.h diff -u src/usr.sbin/ldpd/socketops.h:1.2 src/usr.sbin/ldpd/socketops.h:1.3 --- src/usr.sbin/ldpd/socketops.h:1.2 Tue Jun 14 11:28:51 2011 +++ src/usr.sbin/ldpd/socketops.h Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: socketops.h,v 1.2 2011/06/14 11:28:51 kefren Exp $ */ +/* $NetBSD: socketops.h,v 1.3 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -42,11 +42,7 @@ #define LDP_AF_INET6 2 int set_ttl(int); -int set_mcast_ttl(int); -int set_tos(int); -int socket_reuse_port(int); -int bind_socket(int, uint32_t); -int create_hello_socket(void); +int create_hello_sockets(void); int create_listening_socket(void); void send_hello(void); int get_message_id(void); Index: src/usr.sbin/ldpd/tlv_stack.c diff -u src/usr.sbin/ldpd/tlv_stack.c:1.4 src/usr.sbin/ldpd/tlv_stack.c:1.5 --- src/usr.sbin/ldpd/tlv_stack.c:1.4 Wed Jun 15 18:16:48 2011 +++ src/usr.sbin/ldpd/tlv_stack.c Mon Nov 12 18:39:00 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: tlv_stack.c,v 1.4 2011/06/15 18:16:48 kefren Exp $ */ +/* $NetBSD: tlv_stack.c,v 1.5 2012/11/12 18:39:00 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -253,8 +253,8 @@ send_label_tlv(struct ldp_peer * peer, s /* Now let's do the even a dirtier job: PREFIX TLV */ p = (struct prefix_tlv *) & fec[1]; - /* Cisco and Juniper don't support FEC type HOST - * so everything is FEC_PREFIX.. + /* + * RFC5036 obsoletes FEC_HOST * * if (prefixlen == 32) p->type = FEC_HOST; else */ @@ -344,7 +344,8 @@ send_withdraw_tlv(struct ldp_peer * peer /* Now the even dirtier job: PREFIX TLV */ p = (struct prefix_tlv *) & fec[1]; - /* See above comment + /* + * RFC5036 obsoletes FEC_HOST * * if (prefixlen == 32) p->type = FEC_HOST; else */