Home | History | Annotate | Download | only in net
      1 // Copyright 2011 The Go Authors.  All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package net
      6 
      7 import (
      8 	"os"
      9 	"syscall"
     10 )
     11 
     12 // interfaceMulticastAddrTable returns addresses for a specific
     13 // interface.
     14 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
     15 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
     16 	if err != nil {
     17 		return nil, os.NewSyscallError("routerib", err)
     18 	}
     19 	msgs, err := syscall.ParseRoutingMessage(tab)
     20 	if err != nil {
     21 		return nil, os.NewSyscallError("parseroutingmessage", err)
     22 	}
     23 	var ifmat []Addr
     24 	for _, m := range msgs {
     25 		switch m := m.(type) {
     26 		case *syscall.InterfaceMulticastAddrMessage:
     27 			if ifi.Index == int(m.Header.Index) {
     28 				ifma, err := newMulticastAddr(ifi, m)
     29 				if err != nil {
     30 					return nil, err
     31 				}
     32 				if ifma != nil {
     33 					ifmat = append(ifmat, ifma)
     34 				}
     35 			}
     36 		}
     37 	}
     38 	return ifmat, nil
     39 }
     40 
     41 func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
     42 	sas, err := syscall.ParseRoutingSockaddr(m)
     43 	if err != nil {
     44 		return nil, os.NewSyscallError("parseroutingsockaddr", err)
     45 	}
     46 	switch sa := sas[syscall.RTAX_IFA].(type) {
     47 	case *syscall.SockaddrInet4:
     48 		return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
     49 	case *syscall.SockaddrInet6:
     50 		ifma := IPAddr{IP: make(IP, IPv6len)}
     51 		copy(ifma.IP, sa.Addr[:])
     52 		// NOTE: KAME based IPv6 protcol stack usually embeds
     53 		// the interface index in the interface-local or
     54 		// link-local address as the kernel-internal form.
     55 		if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
     56 			ifma.IP[2], ifma.IP[3] = 0, 0
     57 		}
     58 		return &ifma, nil
     59 	default:
     60 		return nil, nil
     61 	}
     62 }
     63