From c20a7603ebe7f3246901e85d22ccc6476bcfbc96 Mon Sep 17 00:00:00 2001 From: Anatole Denis Date: Tue, 17 Sep 2019 11:18:47 +0200 Subject: server6: Fix listening on multicast addresses Joining a multicast group with an address that can't be received on a socket is ineffective, at least on linux. This updates the logic of NewServer in a mostly backwards-compatible way, to enable listening on arbitrary multicast addresses: * Unicast addresses see no user-visible change, but don't join a multicast group for which they don't receive traffic anyway * Multicast addresses start actually receiving traffic for the group they represent, and don't join the default group. **this is a behaviour change**: previously they would receive traffic for the default group if it was on the same port and **not** for the group they represent. I consider that previous behaviour a bug * Wildcard addresses, if on the proper port, will join both AllDHCPRelayAgentsAndServers and AllDHCPServers **this is a behaviour change**: previously only AllDHCPRelayAgentsAndServers was joined * Wildcard addresses on another port: no visible change, same as unicast case Signed-off-by: Anatole Denis --- dhcpv6/server6/server.go | 53 +++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 19 deletions(-) (limited to 'dhcpv6/server6/server.go') diff --git a/dhcpv6/server6/server.go b/dhcpv6/server6/server.go index ab9cb32..4506195 100644 --- a/dhcpv6/server6/server.go +++ b/dhcpv6/server6/server.go @@ -126,31 +126,46 @@ func NewServer(ifname string, addr *net.UDPAddr, handler Handler, opt ...ServerO o(s) } - if s.conn == nil { - // no connection provided by the user, create a new one - conn, err := net.ListenUDP("udp6", addr) + if s.conn != nil { + return s, nil + } + + var err error + // no connection provided by the user, create a new one + s.conn, err = net.ListenUDP("udp6", addr) + if err != nil { + return nil, err + } + + var iface *net.Interface + if ifname == "" { + iface = nil + } else { + iface, err = net.InterfaceByName(ifname) if err != nil { return nil, err } - // join multicast group on the specified interface - var iface *net.Interface - if ifname == "" { - iface = nil - } else { - iface, err = net.InterfaceByName(ifname) - if err != nil { + } + + p := ipv6.NewPacketConn(s.conn) + if addr.IP.IsMulticast() { + if err := p.JoinGroup(iface, addr); err != nil { + return nil, err + } + } else if addr.IP.IsUnspecified() && addr.Port == dhcpv6.DefaultServerPort { + // For wildcard addresses on the correct port, listen on both multicast + // addresses defined in the RFC as a "default" behaviour + for _, g := range []net.IP{dhcpv6.AllDHCPRelayAgentsAndServers, dhcpv6.AllDHCPServers} { + group := net.UDPAddr{ + IP: g, + Port: dhcpv6.DefaultServerPort, + } + if err := p.JoinGroup(iface, &group); err != nil { return nil, err } + } - group := net.UDPAddr{ - IP: dhcpv6.AllDHCPRelayAgentsAndServers, - Port: dhcpv6.DefaultServerPort, - } - p := ipv6.NewPacketConn(conn) - if err := p.JoinGroup(iface, &group); err != nil { - return nil, err - } - s.conn = conn } + return s, nil } -- cgit v1.2.3