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//go:build darwin || dragonfly || freebsd || netbsd || openbsd
6
7package net
8
9import (
10	"syscall"
11
12	"golang.org/x/net/route"
13)
14
15// If the ifindex is zero, interfaceTable returns mappings of all
16// network interfaces. Otherwise it returns a mapping of a specific
17// interface.
18func interfaceTable(ifindex int) ([]Interface, error) {
19	msgs, err := interfaceMessages(ifindex)
20	if err != nil {
21		return nil, err
22	}
23	n := len(msgs)
24	if ifindex != 0 {
25		n = 1
26	}
27	ift := make([]Interface, n)
28	n = 0
29	for _, m := range msgs {
30		switch m := m.(type) {
31		case *route.InterfaceMessage:
32			if ifindex != 0 && ifindex != m.Index {
33				continue
34			}
35			ift[n].Index = m.Index
36			ift[n].Name = m.Name
37			ift[n].Flags = linkFlags(m.Flags)
38			if sa, ok := m.Addrs[syscall.RTAX_IFP].(*route.LinkAddr); ok && len(sa.Addr) > 0 {
39				ift[n].HardwareAddr = make([]byte, len(sa.Addr))
40				copy(ift[n].HardwareAddr, sa.Addr)
41			}
42			for _, sys := range m.Sys() {
43				if imx, ok := sys.(*route.InterfaceMetrics); ok {
44					ift[n].MTU = imx.MTU
45					break
46				}
47			}
48			n++
49			if ifindex == m.Index {
50				return ift[:n], nil
51			}
52		}
53	}
54	return ift[:n], nil
55}
56
57func linkFlags(rawFlags int) Flags {
58	var f Flags
59	if rawFlags&syscall.IFF_UP != 0 {
60		f |= FlagUp
61	}
62	if rawFlags&syscall.IFF_RUNNING != 0 {
63		f |= FlagRunning
64	}
65	if rawFlags&syscall.IFF_BROADCAST != 0 {
66		f |= FlagBroadcast
67	}
68	if rawFlags&syscall.IFF_LOOPBACK != 0 {
69		f |= FlagLoopback
70	}
71	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
72		f |= FlagPointToPoint
73	}
74	if rawFlags&syscall.IFF_MULTICAST != 0 {
75		f |= FlagMulticast
76	}
77	return f
78}
79
80// If the ifi is nil, interfaceAddrTable returns addresses for all
81// network interfaces. Otherwise it returns addresses for a specific
82// interface.
83func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
84	index := 0
85	if ifi != nil {
86		index = ifi.Index
87	}
88	msgs, err := interfaceMessages(index)
89	if err != nil {
90		return nil, err
91	}
92	ifat := make([]Addr, 0, len(msgs))
93	for _, m := range msgs {
94		switch m := m.(type) {
95		case *route.InterfaceAddrMessage:
96			if index != 0 && index != m.Index {
97				continue
98			}
99			var mask IPMask
100			switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) {
101			case *route.Inet4Addr:
102				mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
103			case *route.Inet6Addr:
104				mask = make(IPMask, IPv6len)
105				copy(mask, sa.IP[:])
106			}
107			var ip IP
108			switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
109			case *route.Inet4Addr:
110				ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
111			case *route.Inet6Addr:
112				ip = make(IP, IPv6len)
113				copy(ip, sa.IP[:])
114			}
115			if ip != nil && mask != nil { // NetBSD may contain route.LinkAddr
116				ifat = append(ifat, &IPNet{IP: ip, Mask: mask})
117			}
118		}
119	}
120	return ifat, nil
121}
122