1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package netutil
19
20 import (
21 "bytes"
22 "encoding/binary"
23 "fmt"
24 "net"
25 "sort"
26 "syscall"
27
28 "go.etcd.io/etcd/pkg/v3/cpuutil"
29 )
30
31 var errNoDefaultRoute = fmt.Errorf("could not find default route")
32 var errNoDefaultHost = fmt.Errorf("could not find default host")
33 var errNoDefaultInterface = fmt.Errorf("could not find default interface")
34
35
36
37 func GetDefaultHost() (string, error) {
38 rmsgs, rerr := getDefaultRoutes()
39 if rerr != nil {
40 return "", rerr
41 }
42
43
44 if rmsg, ok := rmsgs[syscall.AF_INET]; ok {
45 if host, err := chooseHost(syscall.AF_INET, rmsg); host != "" || err != nil {
46 return host, err
47 }
48 delete(rmsgs, syscall.AF_INET)
49 }
50
51
52 var families []int
53 for family := range rmsgs {
54 families = append(families, int(family))
55 }
56 sort.Ints(families)
57
58 for _, f := range families {
59 family := uint8(f)
60 if host, err := chooseHost(family, rmsgs[family]); host != "" || err != nil {
61 return host, err
62 }
63 }
64
65 return "", errNoDefaultHost
66 }
67
68 func chooseHost(family uint8, rmsg *syscall.NetlinkMessage) (string, error) {
69 host, oif, err := parsePREFSRC(rmsg)
70 if host != "" || err != nil {
71 return host, err
72 }
73
74
75 ifmsg, ierr := getIfaceAddr(oif, family)
76 if ierr != nil {
77 return "", ierr
78 }
79
80 attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
81 if aerr != nil {
82 return "", aerr
83 }
84
85 for _, attr := range attrs {
86
87 if attr.Attr.Type == syscall.RTA_DST {
88 return net.IP(attr.Value).String(), nil
89 }
90 }
91
92 return "", nil
93 }
94
95 func getDefaultRoutes() (map[uint8]*syscall.NetlinkMessage, error) {
96 dat, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC)
97 if err != nil {
98 return nil, err
99 }
100
101 msgs, msgErr := syscall.ParseNetlinkMessage(dat)
102 if msgErr != nil {
103 return nil, msgErr
104 }
105
106 routes := make(map[uint8]*syscall.NetlinkMessage)
107 rtmsg := syscall.RtMsg{}
108 for _, m := range msgs {
109 if m.Header.Type != syscall.RTM_NEWROUTE {
110 continue
111 }
112 buf := bytes.NewBuffer(m.Data[:syscall.SizeofRtMsg])
113 if rerr := binary.Read(buf, cpuutil.ByteOrder(), &rtmsg); rerr != nil {
114 continue
115 }
116 if rtmsg.Dst_len == 0 && rtmsg.Table == syscall.RT_TABLE_MAIN {
117
118 msg := m
119 routes[rtmsg.Family] = &msg
120 }
121 }
122
123 if len(routes) > 0 {
124 return routes, nil
125 }
126
127 return nil, errNoDefaultRoute
128 }
129
130
131 func getIfaceAddr(idx uint32, family uint8) (*syscall.NetlinkMessage, error) {
132 dat, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, int(family))
133 if err != nil {
134 return nil, err
135 }
136
137 msgs, msgErr := syscall.ParseNetlinkMessage(dat)
138 if msgErr != nil {
139 return nil, msgErr
140 }
141
142 ifaddrmsg := syscall.IfAddrmsg{}
143 for _, m := range msgs {
144 if m.Header.Type != syscall.RTM_NEWADDR {
145 continue
146 }
147 buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfAddrmsg])
148 if rerr := binary.Read(buf, cpuutil.ByteOrder(), &ifaddrmsg); rerr != nil {
149 continue
150 }
151 if ifaddrmsg.Index == idx {
152 return &m, nil
153 }
154 }
155
156 return nil, fmt.Errorf("could not find address for interface index %v", idx)
157
158 }
159
160
161 func getIfaceLink(idx uint32) (*syscall.NetlinkMessage, error) {
162 dat, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
163 if err != nil {
164 return nil, err
165 }
166
167 msgs, msgErr := syscall.ParseNetlinkMessage(dat)
168 if msgErr != nil {
169 return nil, msgErr
170 }
171
172 ifinfomsg := syscall.IfInfomsg{}
173 for _, m := range msgs {
174 if m.Header.Type != syscall.RTM_NEWLINK {
175 continue
176 }
177 buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfInfomsg])
178 if rerr := binary.Read(buf, cpuutil.ByteOrder(), &ifinfomsg); rerr != nil {
179 continue
180 }
181 if ifinfomsg.Index == int32(idx) {
182 return &m, nil
183 }
184 }
185
186 return nil, fmt.Errorf("could not find link for interface index %v", idx)
187 }
188
189
190 func GetDefaultInterfaces() (map[string]uint8, error) {
191 interfaces := make(map[string]uint8)
192 rmsgs, rerr := getDefaultRoutes()
193 if rerr != nil {
194 return interfaces, rerr
195 }
196
197 for family, rmsg := range rmsgs {
198 _, oif, err := parsePREFSRC(rmsg)
199 if err != nil {
200 return interfaces, err
201 }
202
203 ifmsg, ierr := getIfaceLink(oif)
204 if ierr != nil {
205 return interfaces, ierr
206 }
207
208 attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
209 if aerr != nil {
210 return interfaces, aerr
211 }
212
213 for _, attr := range attrs {
214 if attr.Attr.Type == syscall.IFLA_IFNAME {
215
216
217 interfaces[string(attr.Value[:len(attr.Value)-1])] += family
218 }
219 }
220 }
221 if len(interfaces) > 0 {
222 return interfaces, nil
223 }
224 return interfaces, errNoDefaultInterface
225 }
226
227
228 func parsePREFSRC(m *syscall.NetlinkMessage) (host string, oif uint32, err error) {
229 var attrs []syscall.NetlinkRouteAttr
230 attrs, err = syscall.ParseNetlinkRouteAttr(m)
231 if err != nil {
232 return "", 0, err
233 }
234
235 for _, attr := range attrs {
236 if attr.Attr.Type == syscall.RTA_PREFSRC {
237 host = net.IP(attr.Value).String()
238 }
239 if attr.Attr.Type == syscall.RTA_OIF {
240 oif = cpuutil.ByteOrder().Uint32(attr.Value)
241 }
242 if host != "" && oif != uint32(0) {
243 break
244 }
245 }
246
247 if oif == 0 {
248 err = errNoDefaultRoute
249 }
250 return host, oif, err
251 }
252
View as plain text