diff --git a/dhcp-bindtodevice-inet6.patch b/dhcp-bindtodevice-inet6.patch deleted file mode 100644 index ff548d7..0000000 --- a/dhcp-bindtodevice-inet6.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up dhcp-4.2.5/common/socket.c.bindtodevice_inet6 dhcp-4.2.5/common/socket.c ---- dhcp-4.2.5/common/socket.c.bindtodevice_inet6 2013-09-17 16:47:05.000000000 +0200 -+++ dhcp-4.2.5/common/socket.c 2013-09-17 16:48:18.975997842 +0200 -@@ -245,7 +245,7 @@ if_register_socket(struct interface_info - - #if defined(SO_BINDTODEVICE) - /* Bind this socket to this interface. */ -- if ((local_family != AF_INET6) && (info->ifp != NULL) && -+ if (((do_multicast == 0)||(*do_multicast == 0)) && (info->ifp != NULL) && - setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, - (char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) { - log_fatal("setsockopt: SO_BINDTODEVICE: %m"); diff --git a/dhcp-dhclient6-bind.patch b/dhcp-dhclient6-bind.patch new file mode 100644 index 0000000..9451928 --- /dev/null +++ b/dhcp-dhclient6-bind.patch @@ -0,0 +1,329 @@ +From 198a1fcc9f6f8c39ddf8c6e962b7e4925d43072c Mon Sep 17 00:00:00 2001 +From: Jiri Popelka +Date: Thu, 24 Oct 2013 10:03:52 +0200 +Subject: [PATCH] Fix the socket handling for DHCPv6 clients to allow multiple + instances + +of a client on a single machine to work properly. Previously only +one client would receive the packets. Thanks to Jiri Popelka at Red +Hat for the bug report and a potential patch. +[ISC-Bugs #34784] +--- + common/discover.c | 19 ++++----- + common/socket.c | 116 ++++++++++++++++++++++++++++++++++++++++++++---------- + includes/dhcpd.h | 6 +-- + 3 files changed, 107 insertions(+), 34 deletions(-) + +diff --git a/common/discover.c b/common/discover.c +index a305d92..4027d1a 100644 +--- a/common/discover.c ++++ b/common/discover.c +@@ -57,10 +57,6 @@ struct in_addr limited_broadcast; + int local_family = AF_INET; + struct in_addr local_address; + +-#ifdef DHCPv6 +-struct in6_addr local_address6; +-#endif /* DHCPv6 */ +- + void (*bootp_packet_handler) (struct interface_info *, + struct dhcp_packet *, unsigned, + unsigned int, +@@ -877,7 +873,7 @@ discover_interfaces(int state) { + (state == DISCOVER_RELAY)) { + if_register6(tmp, 1); + } else { +- if_register6(tmp, 0); ++ if_register_linklocal6(tmp); + } + #endif /* DHCPv6 */ + } +@@ -933,13 +929,14 @@ discover_interfaces(int state) { + tmp -> name, isc_result_totext (status)); + + #if defined(DHCPv6) +- /* Only register the first interface for V6, since they all +- * use the same socket. XXX: This has some messy side +- * effects if we start dynamically adding and removing +- * interfaces, but we're well beyond that point in terms of +- * mess. ++ /* Only register the first interface for V6, since ++ * servers and relays all use the same socket. ++ * XXX: This has some messy side effects if we start ++ * dynamically adding and removing interfaces, but ++ * we're well beyond that point in terms of mess. + */ +- if (local_family == AF_INET6) ++ if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) && ++ (local_family == AF_INET6)) + break; + #endif + } /* for (tmp = interfaces; ... */ +diff --git a/common/socket.c b/common/socket.c +index 8fead01..f0c2c94 100644 +--- a/common/socket.c ++++ b/common/socket.c +@@ -67,6 +67,7 @@ + * XXX: this is gross. we need to go back and overhaul the API for socket + * handling. + */ ++static int no_global_v6_socket = 0; + static unsigned int global_v6_socket_references = 0; + static int global_v6_socket = -1; + +@@ -127,7 +128,7 @@ void if_reinitialize_receive (info) + /* Generic interface registration routine... */ + int + if_register_socket(struct interface_info *info, int family, +- int *do_multicast) ++ int *do_multicast, struct in6_addr *linklocal6) + { + struct sockaddr_storage name; + int name_len; +@@ -161,10 +162,12 @@ if_register_socket(struct interface_info *info, int family, + addr6 = (struct sockaddr_in6 *)&name; + addr6->sin6_family = AF_INET6; + addr6->sin6_port = local_port; +- /* XXX: What will happen to multicasts if this is nonzero? */ +- memcpy(&addr6->sin6_addr, +- &local_address6, +- sizeof(addr6->sin6_addr)); ++ if (linklocal6) { ++ memcpy(&addr6->sin6_addr, ++ linklocal6, ++ sizeof(addr6->sin6_addr)); ++ addr6->sin6_scope_id = if_nametoindex(info->name); ++ } + #ifdef HAVE_SA_LEN + addr6->sin6_len = sizeof(*addr6); + #endif +@@ -221,9 +224,9 @@ if_register_socket(struct interface_info *info, int family, + * daemons can bind to their own sockets and get data for their + * respective interfaces. This does not (and should not) affect + * DHCPv4 sockets; we can't yet support BSD sockets well, much +- * less multiple sockets. ++ * less multiple sockets. Make sense only with multicast. + */ +- if (local_family == AF_INET6) { ++ if (local_family == AF_INET6 && *do_multicast) { + flag = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, + (char *)&flag, sizeof(flag)) < 0) { +@@ -322,7 +325,7 @@ void if_register_send (info) + struct interface_info *info; + { + #ifndef USE_SOCKET_RECEIVE +- info->wfdesc = if_register_socket(info, AF_INET, 0); ++ info->wfdesc = if_register_socket(info, AF_INET, 0, NULL); + /* If this is a normal IPv4 address, get the hardware address. */ + if (strcmp(info->name, "fallback") != 0) + get_hw_addr(info); +@@ -368,7 +371,7 @@ void if_register_receive (info) + + #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) + if (global_v4_socket_references == 0) { +- global_v4_socket = if_register_socket(info, AF_INET, 0); ++ global_v4_socket = if_register_socket(info, AF_INET, 0, NULL); + if (global_v4_socket < 0) { + /* + * if_register_socket() fatally logs if it fails to +@@ -384,7 +387,7 @@ void if_register_receive (info) + #else + /* If we're using the socket API for sending and receiving, + we don't need to register this interface twice. */ +- info->rfdesc = if_register_socket(info, AF_INET, 0); ++ info->rfdesc = if_register_socket(info, AF_INET, 0, NULL); + #endif /* IP_PKTINFO... */ + /* If this is a normal IPv4 address, get the hardware address. */ + if (strcmp(info->name, "fallback") != 0) +@@ -477,9 +480,13 @@ if_register6(struct interface_info *info, int do_multicast) { + /* Bounce do_multicast to a stack variable because we may change it. */ + int req_multi = do_multicast; + ++ if (no_global_v6_socket) { ++ log_fatal("Impossible condition at %s:%d", MDL); ++ } ++ + if (global_v6_socket_references == 0) { + global_v6_socket = if_register_socket(info, AF_INET6, +- &req_multi); ++ &req_multi, NULL); + if (global_v6_socket < 0) { + /* + * if_register_socket() fatally logs if it fails to +@@ -515,12 +522,73 @@ if_register6(struct interface_info *info, int do_multicast) { + } + } + ++/* ++ * Register an IPv6 socket bound to the link-local address of ++ * the argument interface (used by clients on a multiple interface box, ++ * vs. a server or a relay using the global IPv6 socket and running ++ * *only* in a single instance). ++ */ ++void ++if_register_linklocal6(struct interface_info *info) { ++ int sock; ++ int count; ++ struct in6_addr *addr6 = NULL; ++ int req_multi = 0; ++ ++ if (global_v6_socket >= 0) { ++ log_fatal("Impossible condition at %s:%d", MDL); ++ } ++ ++ no_global_v6_socket = 1; ++ ++ /* get the (?) link-local address */ ++ for (count = 0; count < info->v6address_count; count++) { ++ addr6 = &info->v6addresses[count]; ++ if (IN6_IS_ADDR_LINKLOCAL(addr6)) ++ break; ++ } ++ ++ if (!addr6) { ++ log_fatal("no link-local IPv6 address for %s", info->name); ++ } ++ ++ sock = if_register_socket(info, AF_INET6, &req_multi, addr6); ++ ++ if (sock < 0) { ++ log_fatal("if_register_socket for %s fails", info->name); ++ } ++ ++ info->rfdesc = sock; ++ info->wfdesc = sock; ++ ++ get_hw_addr(info); ++ ++ if (!quiet_interface_discovery) { ++ if (info->shared_network != NULL) { ++ log_info("Listening on Socket/%d/%s/%s", ++ global_v6_socket, info->name, ++ info->shared_network->name); ++ log_info("Sending on Socket/%d/%s/%s", ++ global_v6_socket, info->name, ++ info->shared_network->name); ++ } else { ++ log_info("Listening on Socket/%s", info->name); ++ log_info("Sending on Socket/%s", info->name); ++ } ++ } ++} ++ + void + if_deregister6(struct interface_info *info) { +- /* Dereference the global v6 socket. */ +- if ((info->rfdesc == global_v6_socket) && +- (info->wfdesc == global_v6_socket) && +- (global_v6_socket_references > 0)) { ++ /* client case */ ++ if (no_global_v6_socket) { ++ close(info->rfdesc); ++ info->rfdesc = -1; ++ info->wfdesc = -1; ++ } else if ((info->rfdesc == global_v6_socket) && ++ (info->wfdesc == global_v6_socket) && ++ (global_v6_socket_references > 0)) { ++ /* Dereference the global v6 socket. */ + global_v6_socket_references--; + info->rfdesc = -1; + info->wfdesc = -1; +@@ -540,7 +608,8 @@ if_deregister6(struct interface_info *info) { + } + } + +- if (global_v6_socket_references == 0) { ++ if (!no_global_v6_socket && ++ (global_v6_socket_references == 0)) { + close(global_v6_socket); + global_v6_socket = -1; + +@@ -692,9 +761,11 @@ ssize_t send_packet6(struct interface_info *interface, + struct sockaddr_in6 *to) { + struct msghdr m; + struct iovec v; ++ struct sockaddr_in6 dst; + int result; + struct in6_pktinfo *pktinfo; + struct cmsghdr *cmsg; ++ unsigned int ifindex; + + /* + * If necessary allocate space for the control message header. +@@ -717,9 +788,14 @@ ssize_t send_packet6(struct interface_info *interface, + + /* + * Set the target address we're sending to. ++ * Enforce the scope ID for bogus BSDs. + */ +- m.msg_name = to; +- m.msg_namelen = sizeof(*to); ++ memcpy(&dst, to, sizeof(dst)); ++ m.msg_name = &dst; ++ m.msg_namelen = sizeof(dst); ++ ifindex = if_nametoindex(interface->name); ++ if (no_global_v6_socket) ++ dst.sin6_scope_id = ifindex; + + /* + * Set the data buffer we're sending. (Using this wacky +@@ -747,7 +823,7 @@ ssize_t send_packet6(struct interface_info *interface, + cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo)); + pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); + memset(pktinfo, 0, sizeof(*pktinfo)); +- pktinfo->ipi6_ifindex = if_nametoindex(interface->name); ++ pktinfo->ipi6_ifindex = ifindex; + m.msg_controllen = cmsg->cmsg_len; + + result = sendmsg(interface->wfdesc, &m, 0); +@@ -1046,7 +1122,7 @@ void maybe_setup_fallback () + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { +- fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0); ++ fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0, NULL); + fbi -> rfdesc = fbi -> wfdesc; + log_info ("Sending on Socket/%s%s%s", + fbi -> name, +diff --git a/includes/dhcpd.h b/includes/dhcpd.h +index b2fbc8b..56d4eab 100644 +--- a/includes/dhcpd.h ++++ b/includes/dhcpd.h +@@ -2378,7 +2378,7 @@ void get_hw_addr(struct interface_info *info); + /* socket.c */ + #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \ + || defined (USE_SOCKET_FALLBACK) +-int if_register_socket(struct interface_info *, int, int *); ++int if_register_socket(struct interface_info *, int, int *, struct in6_addr *); + #endif + + #if defined (USE_SOCKET_FALLBACK) && !defined (USE_SOCKET_SEND) +@@ -2389,7 +2389,7 @@ ssize_t send_fallback (struct interface_info *, + struct in_addr, + struct sockaddr_in *, struct hardware *); + ssize_t send_fallback6(struct interface_info *, struct packet *, +- struct dhcp_packet *, size_t, struct in6_addr, ++ struct dhcp_packet *, size_t, struct in6_addr *, + struct sockaddr_in6 *, struct hardware *); + #endif + +@@ -2425,6 +2425,7 @@ void maybe_setup_fallback (void); + #endif + + void if_register6(struct interface_info *info, int do_multicast); ++void if_register_linklocal6(struct interface_info *info); + ssize_t receive_packet6(struct interface_info *interface, + unsigned char *buf, size_t len, + struct sockaddr_in6 *from, struct in6_addr *to_addr, +@@ -2570,7 +2571,6 @@ void interface_trace_setup (void); + extern struct in_addr limited_broadcast; + extern int local_family; + extern struct in_addr local_address; +-extern struct in6_addr local_address6; + + extern u_int16_t local_port; + extern u_int16_t remote_port; +-- +1.8.3.1 + diff --git a/dhcp.spec b/dhcp.spec index 9414e1e..9446e78 100644 --- a/dhcp.spec +++ b/dhcp.spec @@ -18,7 +18,7 @@ Summary: Dynamic host configuration protocol software Name: dhcp Version: 4.2.5 -Release: 24%{?dist} +Release: 25%{?dist} # NEVER CHANGE THE EPOCH on this package. The previous maintainer (prior to # dcantrell maintaining the package) made incorrect use of the epoch and # that's why it is at 12 now. It should have never been used, but it was. @@ -79,7 +79,7 @@ Patch45: dhcp-4.2.4-P2-conflex-do-forward-updates.patch Patch46: dhcp-4.2.4-P2-dupl-key.patch Patch47: dhcp-4.2.5-range6.patch Patch48: dhcp-4.2.5-next-server.patch -Patch49: dhcp-bindtodevice-inet6.patch +Patch49: dhcp-dhclient6-bind.patch Patch50: dhcp-no-subnet-error2info.patch Patch51: dhcp-ffff-checksum.patch @@ -348,7 +348,7 @@ rm -rf includes/isc-dhcp # dhclient -6: bind socket to interface (#1001742) # (Submitted to dhcp-bugs@isc.org - [ISC-Bugs #34784]) -%patch49 -p1 -b .bindtodevice_inet6 +%patch49 -p1 -b .dhclient6-bind # 'No subnet declaration for ' should be info, not error. %patch50 -p1 -b .error2info @@ -624,6 +624,9 @@ done %changelog +* Thu Oct 24 2013 Jiri Popelka - 12:4.2.5-25 +- use upstream patch for #1001742 ([ISC-Bugs #34784]) + * Mon Oct 07 2013 Jiri Popelka - 12:4.2.5-24 - dhcpd rejects the udp packet with checksum=0xffff (#1015997)