1
2
3
4
5
6
7 package lif
8
9 import (
10 "syscall"
11 "unsafe"
12 )
13
14
15
16
17
18
19
20
21 type Link struct {
22 Name string
23 Index int
24 Type int
25 Flags int
26 MTU int
27 Addr []byte
28 }
29
30 func (ll *Link) fetch(s uintptr) {
31 var lifr lifreq
32 for i := 0; i < len(ll.Name); i++ {
33 lifr.Name[i] = int8(ll.Name[i])
34 }
35 ioc := int64(syscall.SIOCGLIFINDEX)
36 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
37 ll.Index = int(nativeEndian.Uint32(lifr.Lifru[:4]))
38 }
39 ioc = int64(syscall.SIOCGLIFFLAGS)
40 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
41 ll.Flags = int(nativeEndian.Uint64(lifr.Lifru[:8]))
42 }
43 ioc = int64(syscall.SIOCGLIFMTU)
44 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
45 ll.MTU = int(nativeEndian.Uint32(lifr.Lifru[:4]))
46 }
47 switch ll.Type {
48 case syscall.IFT_IPV4, syscall.IFT_IPV6, syscall.IFT_6TO4:
49 default:
50 ioc = int64(syscall.SIOCGLIFHWADDR)
51 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
52 ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:])
53 }
54 }
55 }
56
57
58
59
60
61 func Links(af int, name string) ([]Link, error) {
62 eps, err := newEndpoints(af)
63 if len(eps) == 0 {
64 return nil, err
65 }
66 defer func() {
67 for _, ep := range eps {
68 ep.close()
69 }
70 }()
71 return links(eps, name)
72 }
73
74 func links(eps []endpoint, name string) ([]Link, error) {
75 var lls []Link
76 lifn := lifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
77 lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
78 for _, ep := range eps {
79 lifn.Family = uint16(ep.af)
80 ioc := int64(syscall.SIOCGLIFNUM)
81 if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil {
82 continue
83 }
84 if lifn.Count == 0 {
85 continue
86 }
87 b := make([]byte, lifn.Count*sizeofLifreq)
88 lifc.Family = uint16(ep.af)
89 lifc.Len = lifn.Count * sizeofLifreq
90 if len(lifc.Lifcu) == 8 {
91 nativeEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0]))))
92 } else {
93 nativeEndian.PutUint32(lifc.Lifcu[:], uint32(uintptr(unsafe.Pointer(&b[0]))))
94 }
95 ioc = int64(syscall.SIOCGLIFCONF)
96 if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
97 continue
98 }
99 nb := make([]byte, 32)
100 for i := 0; i < int(lifn.Count); i++ {
101 lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq]))
102 for i := 0; i < 32; i++ {
103 if lifr.Name[i] == 0 {
104 nb = nb[:i]
105 break
106 }
107 nb[i] = byte(lifr.Name[i])
108 }
109 llname := string(nb)
110 nb = nb[:32]
111 if isDupLink(lls, llname) || name != "" && name != llname {
112 continue
113 }
114 ll := Link{Name: llname, Type: int(lifr.Type)}
115 ll.fetch(ep.s)
116 lls = append(lls, ll)
117 }
118 }
119 return lls, nil
120 }
121
122 func isDupLink(lls []Link, name string) bool {
123 for _, ll := range lls {
124 if ll.Name == name {
125 return true
126 }
127 }
128 return false
129 }
130
View as plain text