1 package netlink
2
3 import (
4 "fmt"
5 "net"
6 "strings"
7 "syscall"
8
9 "github.com/vishvananda/netlink/nl"
10 "github.com/vishvananda/netns"
11 "golang.org/x/sys/unix"
12 )
13
14
15
16
17
18
19
20 func AddrAdd(link Link, addr *Addr) error {
21 return pkgHandle.AddrAdd(link, addr)
22 }
23
24
25
26
27
28
29
30 func (h *Handle) AddrAdd(link Link, addr *Addr) error {
31 req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
32 return h.addrHandle(link, addr, req)
33 }
34
35
36
37
38
39
40
41 func AddrReplace(link Link, addr *Addr) error {
42 return pkgHandle.AddrReplace(link, addr)
43 }
44
45
46
47
48
49
50
51 func (h *Handle) AddrReplace(link Link, addr *Addr) error {
52 req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
53 return h.addrHandle(link, addr, req)
54 }
55
56
57
58
59
60
61
62 func AddrDel(link Link, addr *Addr) error {
63 return pkgHandle.AddrDel(link, addr)
64 }
65
66
67
68
69
70
71 func (h *Handle) AddrDel(link Link, addr *Addr) error {
72 req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
73 return h.addrHandle(link, addr, req)
74 }
75
76 func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
77 family := nl.GetIPFamily(addr.IP)
78 msg := nl.NewIfAddrmsg(family)
79 msg.Scope = uint8(addr.Scope)
80 if link == nil {
81 msg.Index = uint32(addr.LinkIndex)
82 } else {
83 base := link.Attrs()
84 if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
85 return fmt.Errorf("label must begin with interface name")
86 }
87 h.ensureIndex(base)
88 msg.Index = uint32(base.Index)
89 }
90 mask := addr.Mask
91 if addr.Peer != nil {
92 mask = addr.Peer.Mask
93 }
94 prefixlen, masklen := mask.Size()
95 msg.Prefixlen = uint8(prefixlen)
96 req.AddData(msg)
97
98 var localAddrData []byte
99 if family == FAMILY_V4 {
100 localAddrData = addr.IP.To4()
101 } else {
102 localAddrData = addr.IP.To16()
103 }
104
105 localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
106 req.AddData(localData)
107 var peerAddrData []byte
108 if addr.Peer != nil {
109 if family == FAMILY_V4 {
110 peerAddrData = addr.Peer.IP.To4()
111 } else {
112 peerAddrData = addr.Peer.IP.To16()
113 }
114 } else {
115 peerAddrData = localAddrData
116 }
117
118 addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
119 req.AddData(addressData)
120
121 if addr.Flags != 0 {
122 if addr.Flags <= 0xff {
123 msg.IfAddrmsg.Flags = uint8(addr.Flags)
124 } else {
125 b := make([]byte, 4)
126 native.PutUint32(b, uint32(addr.Flags))
127 flagsData := nl.NewRtAttr(unix.IFA_FLAGS, b)
128 req.AddData(flagsData)
129 }
130 }
131
132 if family == FAMILY_V4 {
133
134
135
136 if addr.Broadcast == nil && prefixlen < 31 {
137 calcBroadcast := make(net.IP, masklen/8)
138 for i := range localAddrData {
139 calcBroadcast[i] = localAddrData[i] | ^mask[i]
140 }
141 addr.Broadcast = calcBroadcast
142 }
143
144 if addr.Broadcast != nil {
145 req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
146 }
147
148 if addr.Label != "" {
149 labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
150 req.AddData(labelData)
151 }
152 }
153
154
155
156
157 if addr.ValidLft > 0 || addr.PreferedLft > 0 {
158 cachedata := nl.IfaCacheInfo{unix.IfaCacheinfo{
159 Valid: uint32(addr.ValidLft),
160 Prefered: uint32(addr.PreferedLft),
161 }}
162 req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
163 }
164
165 _, err := req.Execute(unix.NETLINK_ROUTE, 0)
166 return err
167 }
168
169
170
171
172 func AddrList(link Link, family int) ([]Addr, error) {
173 return pkgHandle.AddrList(link, family)
174 }
175
176
177
178
179 func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
180 req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
181 msg := nl.NewIfAddrmsg(family)
182 req.AddData(msg)
183
184 msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
185 if err != nil {
186 return nil, err
187 }
188
189 indexFilter := 0
190 if link != nil {
191 base := link.Attrs()
192 h.ensureIndex(base)
193 indexFilter = base.Index
194 }
195
196 var res []Addr
197 for _, m := range msgs {
198 addr, msgFamily, err := parseAddr(m)
199 if err != nil {
200 return res, err
201 }
202
203 if link != nil && addr.LinkIndex != indexFilter {
204
205 continue
206 }
207
208 if family != FAMILY_ALL && msgFamily != family {
209 continue
210 }
211
212 res = append(res, addr)
213 }
214
215 return res, nil
216 }
217
218 func parseAddr(m []byte) (addr Addr, family int, err error) {
219 msg := nl.DeserializeIfAddrmsg(m)
220
221 family = -1
222 addr.LinkIndex = -1
223
224 attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
225 if err1 != nil {
226 err = err1
227 return
228 }
229
230 family = int(msg.Family)
231 addr.LinkIndex = int(msg.Index)
232
233 var local, dst *net.IPNet
234 for _, attr := range attrs {
235 switch attr.Attr.Type {
236 case unix.IFA_ADDRESS:
237 dst = &net.IPNet{
238 IP: attr.Value,
239 Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
240 }
241 case unix.IFA_LOCAL:
242
243
244
245
246
247 n := 8 * len(attr.Value)
248 local = &net.IPNet{
249 IP: attr.Value,
250 Mask: net.CIDRMask(n, n),
251 }
252 case unix.IFA_BROADCAST:
253 addr.Broadcast = attr.Value
254 case unix.IFA_LABEL:
255 addr.Label = string(attr.Value[:len(attr.Value)-1])
256 case unix.IFA_FLAGS:
257 addr.Flags = int(native.Uint32(attr.Value[0:4]))
258 case unix.IFA_CACHEINFO:
259 ci := nl.DeserializeIfaCacheInfo(attr.Value)
260 addr.PreferedLft = int(ci.Prefered)
261 addr.ValidLft = int(ci.Valid)
262 }
263 }
264
265
266
267
268
269
270
271
272 if local != nil {
273 if family == FAMILY_V4 && dst != nil && local.IP.Equal(dst.IP) {
274 addr.IPNet = dst
275 } else {
276 addr.IPNet = local
277 addr.Peer = dst
278 }
279 } else {
280 addr.IPNet = dst
281 }
282
283 addr.Scope = int(msg.Scope)
284
285 return
286 }
287
288 type AddrUpdate struct {
289 LinkAddress net.IPNet
290 LinkIndex int
291 Flags int
292 Scope int
293 PreferedLft int
294 ValidLft int
295 NewAddr bool
296 }
297
298
299
300 func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
301 return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
302 }
303
304
305
306 func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
307 return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
308 }
309
310
311
312 type AddrSubscribeOptions struct {
313 Namespace *netns.NsHandle
314 ErrorCallback func(error)
315 ListExisting bool
316 ReceiveBufferSize int
317 ReceiveBufferForceSize bool
318 ReceiveTimeout *unix.Timeval
319 }
320
321
322
323
324 func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
325 if options.Namespace == nil {
326 none := netns.None()
327 options.Namespace = &none
328 }
329 return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
330 options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
331 }
332
333 func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
334 rcvbuf int, rcvTimeout *unix.Timeval, rcvBufForce bool) error {
335 s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
336 if err != nil {
337 return err
338 }
339 if rcvTimeout != nil {
340 if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
341 return err
342 }
343 }
344 if rcvbuf != 0 {
345 err = s.SetReceiveBufferSize(rcvbuf, rcvBufForce)
346 if err != nil {
347 return err
348 }
349 }
350 if done != nil {
351 go func() {
352 <-done
353 s.Close()
354 }()
355 }
356 if listExisting {
357 req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
358 unix.NLM_F_DUMP)
359 infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
360 req.AddData(infmsg)
361 if err := s.Send(req); err != nil {
362 return err
363 }
364 }
365 go func() {
366 defer close(ch)
367 for {
368 msgs, from, err := s.Receive()
369 if err != nil {
370 if cberr != nil {
371 cberr(fmt.Errorf("Receive failed: %v",
372 err))
373 }
374 return
375 }
376 if from.Pid != nl.PidKernel {
377 if cberr != nil {
378 cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
379 }
380 continue
381 }
382 for _, m := range msgs {
383 if m.Header.Type == unix.NLMSG_DONE {
384 continue
385 }
386 if m.Header.Type == unix.NLMSG_ERROR {
387 error := int32(native.Uint32(m.Data[0:4]))
388 if error == 0 {
389 continue
390 }
391 if cberr != nil {
392 cberr(fmt.Errorf("error message: %v",
393 syscall.Errno(-error)))
394 }
395 continue
396 }
397 msgType := m.Header.Type
398 if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
399 if cberr != nil {
400 cberr(fmt.Errorf("bad message type: %d", msgType))
401 }
402 continue
403 }
404
405 addr, _, err := parseAddr(m.Data)
406 if err != nil {
407 if cberr != nil {
408 cberr(fmt.Errorf("could not parse address: %v", err))
409 }
410 continue
411 }
412
413 ch <- AddrUpdate{LinkAddress: *addr.IPNet,
414 LinkIndex: addr.LinkIndex,
415 NewAddr: msgType == unix.RTM_NEWADDR,
416 Flags: addr.Flags,
417 Scope: addr.Scope,
418 PreferedLft: addr.PreferedLft,
419 ValidLft: addr.ValidLft}
420 }
421 }
422 }()
423
424 return nil
425 }
426
View as plain text