addr_linux.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "strings"
  6. "syscall"
  7. "github.com/vishvananda/netlink/nl"
  8. )
  9. // IFA_FLAGS is a u32 attribute.
  10. const IFA_FLAGS = 0x8
  11. // AddrAdd will add an IP address to a link device.
  12. // Equivalent to: `ip addr add $addr dev $link`
  13. func AddrAdd(link Link, addr *Addr) error {
  14. req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
  15. return addrHandle(link, addr, req)
  16. }
  17. // AddrDel will delete an IP address from a link device.
  18. // Equivalent to: `ip addr del $addr dev $link`
  19. func AddrDel(link Link, addr *Addr) error {
  20. req := nl.NewNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
  21. return addrHandle(link, addr, req)
  22. }
  23. func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
  24. base := link.Attrs()
  25. if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
  26. return fmt.Errorf("label must begin with interface name")
  27. }
  28. ensureIndex(base)
  29. family := nl.GetIPFamily(addr.IP)
  30. msg := nl.NewIfAddrmsg(family)
  31. msg.Index = uint32(base.Index)
  32. msg.Scope = uint8(addr.Scope)
  33. prefixlen, _ := addr.Mask.Size()
  34. msg.Prefixlen = uint8(prefixlen)
  35. req.AddData(msg)
  36. var addrData []byte
  37. if family == FAMILY_V4 {
  38. addrData = addr.IP.To4()
  39. } else {
  40. addrData = addr.IP.To16()
  41. }
  42. localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData)
  43. req.AddData(localData)
  44. addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData)
  45. req.AddData(addressData)
  46. if addr.Flags != 0 {
  47. b := make([]byte, 4)
  48. native.PutUint32(b, uint32(addr.Flags))
  49. flagsData := nl.NewRtAttr(IFA_FLAGS, b)
  50. req.AddData(flagsData)
  51. }
  52. if addr.Label != "" {
  53. labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
  54. req.AddData(labelData)
  55. }
  56. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  57. return err
  58. }
  59. // AddrList gets a list of IP addresses in the system.
  60. // Equivalent to: `ip addr show`.
  61. // The list can be filtered by link and ip family.
  62. func AddrList(link Link, family int) ([]Addr, error) {
  63. req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
  64. msg := nl.NewIfInfomsg(family)
  65. req.AddData(msg)
  66. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
  67. if err != nil {
  68. return nil, err
  69. }
  70. index := 0
  71. if link != nil {
  72. base := link.Attrs()
  73. ensureIndex(base)
  74. index = base.Index
  75. }
  76. var res []Addr
  77. for _, m := range msgs {
  78. msg := nl.DeserializeIfAddrmsg(m)
  79. if link != nil && msg.Index != uint32(index) {
  80. // Ignore messages from other interfaces
  81. continue
  82. }
  83. if family != FAMILY_ALL && msg.Family != uint8(family) {
  84. continue
  85. }
  86. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  87. if err != nil {
  88. return nil, err
  89. }
  90. var local, dst *net.IPNet
  91. var addr Addr
  92. for _, attr := range attrs {
  93. switch attr.Attr.Type {
  94. case syscall.IFA_ADDRESS:
  95. dst = &net.IPNet{
  96. IP: attr.Value,
  97. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  98. }
  99. case syscall.IFA_LOCAL:
  100. local = &net.IPNet{
  101. IP: attr.Value,
  102. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  103. }
  104. case syscall.IFA_LABEL:
  105. addr.Label = string(attr.Value[:len(attr.Value)-1])
  106. case IFA_FLAGS:
  107. addr.Flags = int(native.Uint32(attr.Value[0:4]))
  108. }
  109. }
  110. // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
  111. if local != nil {
  112. addr.IPNet = local
  113. } else {
  114. addr.IPNet = dst
  115. }
  116. addr.Scope = int(msg.Scope)
  117. res = append(res, addr)
  118. }
  119. return res, nil
  120. }