You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

387 lines
8.4 KiB

  1. // Copyright 2016 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. // +build darwin dragonfly freebsd netbsd openbsd
  5. package route
  6. import (
  7. "fmt"
  8. "os/exec"
  9. "runtime"
  10. "time"
  11. )
  12. func (m *RouteMessage) String() string {
  13. return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16])))
  14. }
  15. func (m *InterfaceMessage) String() string {
  16. var attrs addrAttrs
  17. if runtime.GOOS == "openbsd" {
  18. attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
  19. } else {
  20. attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
  21. }
  22. return fmt.Sprintf("%s", attrs)
  23. }
  24. func (m *InterfaceAddrMessage) String() string {
  25. var attrs addrAttrs
  26. if runtime.GOOS == "openbsd" {
  27. attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
  28. } else {
  29. attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
  30. }
  31. return fmt.Sprintf("%s", attrs)
  32. }
  33. func (m *InterfaceMulticastAddrMessage) String() string {
  34. return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8])))
  35. }
  36. func (m *InterfaceAnnounceMessage) String() string {
  37. what := "<nil>"
  38. switch m.What {
  39. case 0:
  40. what = "arrival"
  41. case 1:
  42. what = "departure"
  43. }
  44. return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what)
  45. }
  46. func (m *InterfaceMetrics) String() string {
  47. return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU)
  48. }
  49. func (m *RouteMetrics) String() string {
  50. return fmt.Sprintf("(pmtu=%d)", m.PathMTU)
  51. }
  52. type addrAttrs uint
  53. var addrAttrNames = [...]string{
  54. "dst",
  55. "gateway",
  56. "netmask",
  57. "genmask",
  58. "ifp",
  59. "ifa",
  60. "author",
  61. "brd",
  62. "df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd
  63. "df:mpls2-o:srcmask", // mpls2 for dragonfly, srcmask for openbsd
  64. "df:mpls3-o:label", // mpls3 for dragonfly, label for openbsd
  65. }
  66. func (attrs addrAttrs) String() string {
  67. var s string
  68. for i, name := range addrAttrNames {
  69. if attrs&(1<<uint(i)) != 0 {
  70. if s != "" {
  71. s += "|"
  72. }
  73. s += name
  74. }
  75. }
  76. if s == "" {
  77. return "<nil>"
  78. }
  79. return s
  80. }
  81. type msgs []Message
  82. func (ms msgs) validate() ([]string, error) {
  83. var ss []string
  84. for _, m := range ms {
  85. switch m := m.(type) {
  86. case *RouteMessage:
  87. if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil {
  88. return nil, err
  89. }
  90. sys := m.Sys()
  91. if sys == nil {
  92. return nil, fmt.Errorf("no sys for %s", m.String())
  93. }
  94. ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
  95. case *InterfaceMessage:
  96. var attrs addrAttrs
  97. if runtime.GOOS == "openbsd" {
  98. attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
  99. } else {
  100. attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
  101. }
  102. if err := addrs(m.Addrs).match(attrs); err != nil {
  103. return nil, err
  104. }
  105. sys := m.Sys()
  106. if sys == nil {
  107. return nil, fmt.Errorf("no sys for %s", m.String())
  108. }
  109. ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
  110. case *InterfaceAddrMessage:
  111. var attrs addrAttrs
  112. if runtime.GOOS == "openbsd" {
  113. attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
  114. } else {
  115. attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
  116. }
  117. if err := addrs(m.Addrs).match(attrs); err != nil {
  118. return nil, err
  119. }
  120. ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
  121. case *InterfaceMulticastAddrMessage:
  122. if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil {
  123. return nil, err
  124. }
  125. ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
  126. case *InterfaceAnnounceMessage:
  127. ss = append(ss, m.String())
  128. default:
  129. ss = append(ss, fmt.Sprintf("%+v", m))
  130. }
  131. }
  132. return ss, nil
  133. }
  134. type syss []Sys
  135. func (sys syss) String() string {
  136. var s string
  137. for _, sy := range sys {
  138. switch sy := sy.(type) {
  139. case *InterfaceMetrics:
  140. if len(s) > 0 {
  141. s += " "
  142. }
  143. s += sy.String()
  144. case *RouteMetrics:
  145. if len(s) > 0 {
  146. s += " "
  147. }
  148. s += sy.String()
  149. }
  150. }
  151. return s
  152. }
  153. type addrFamily int
  154. func (af addrFamily) String() string {
  155. switch af {
  156. case sysAF_UNSPEC:
  157. return "unspec"
  158. case sysAF_LINK:
  159. return "link"
  160. case sysAF_INET:
  161. return "inet4"
  162. case sysAF_INET6:
  163. return "inet6"
  164. default:
  165. return fmt.Sprintf("%d", af)
  166. }
  167. }
  168. const hexDigit = "0123456789abcdef"
  169. type llAddr []byte
  170. func (a llAddr) String() string {
  171. if len(a) == 0 {
  172. return ""
  173. }
  174. buf := make([]byte, 0, len(a)*3-1)
  175. for i, b := range a {
  176. if i > 0 {
  177. buf = append(buf, ':')
  178. }
  179. buf = append(buf, hexDigit[b>>4])
  180. buf = append(buf, hexDigit[b&0xF])
  181. }
  182. return string(buf)
  183. }
  184. type ipAddr []byte
  185. func (a ipAddr) String() string {
  186. if len(a) == 0 {
  187. return "<nil>"
  188. }
  189. if len(a) == 4 {
  190. return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3])
  191. }
  192. if len(a) == 16 {
  193. return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15])
  194. }
  195. s := make([]byte, len(a)*2)
  196. for i, tn := range a {
  197. s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
  198. }
  199. return string(s)
  200. }
  201. func (a *LinkAddr) String() string {
  202. name := a.Name
  203. if name == "" {
  204. name = "<nil>"
  205. }
  206. lla := llAddr(a.Addr).String()
  207. if lla == "" {
  208. lla = "<nil>"
  209. }
  210. return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla)
  211. }
  212. func (a *Inet4Addr) String() string {
  213. return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:]))
  214. }
  215. func (a *Inet6Addr) String() string {
  216. return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID)
  217. }
  218. func (a *DefaultAddr) String() string {
  219. return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String())
  220. }
  221. type addrs []Addr
  222. func (as addrs) String() string {
  223. var s string
  224. for _, a := range as {
  225. if a == nil {
  226. continue
  227. }
  228. if len(s) > 0 {
  229. s += " "
  230. }
  231. switch a := a.(type) {
  232. case *LinkAddr:
  233. s += a.String()
  234. case *Inet4Addr:
  235. s += a.String()
  236. case *Inet6Addr:
  237. s += a.String()
  238. case *DefaultAddr:
  239. s += a.String()
  240. }
  241. }
  242. if s == "" {
  243. return "<nil>"
  244. }
  245. return s
  246. }
  247. func (as addrs) match(attrs addrAttrs) error {
  248. var ts addrAttrs
  249. af := sysAF_UNSPEC
  250. for i := range as {
  251. if as[i] != nil {
  252. ts |= 1 << uint(i)
  253. }
  254. switch as[i].(type) {
  255. case *Inet4Addr:
  256. if af == sysAF_UNSPEC {
  257. af = sysAF_INET
  258. }
  259. if af != sysAF_INET {
  260. return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
  261. }
  262. case *Inet6Addr:
  263. if af == sysAF_UNSPEC {
  264. af = sysAF_INET6
  265. }
  266. if af != sysAF_INET6 {
  267. return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
  268. }
  269. }
  270. }
  271. if ts != attrs && ts > attrs {
  272. return fmt.Errorf("%v not included in %v", ts, attrs)
  273. }
  274. return nil
  275. }
  276. func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) {
  277. var err error
  278. var b []byte
  279. for i := 0; i < 3; i++ {
  280. if b, err = FetchRIB(af, typ, 0); err != nil {
  281. time.Sleep(10 * time.Millisecond)
  282. continue
  283. }
  284. break
  285. }
  286. if err != nil {
  287. return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
  288. }
  289. ms, err := ParseRIB(typ, b)
  290. if err != nil {
  291. return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
  292. }
  293. return ms, nil
  294. }
  295. // propVirtual is a proprietary virtual network interface.
  296. type propVirtual struct {
  297. name string
  298. addr, mask string
  299. setupCmds []*exec.Cmd
  300. teardownCmds []*exec.Cmd
  301. }
  302. func (pv *propVirtual) setup() error {
  303. for _, cmd := range pv.setupCmds {
  304. if err := cmd.Run(); err != nil {
  305. pv.teardown()
  306. return err
  307. }
  308. }
  309. return nil
  310. }
  311. func (pv *propVirtual) teardown() error {
  312. for _, cmd := range pv.teardownCmds {
  313. if err := cmd.Run(); err != nil {
  314. return err
  315. }
  316. }
  317. return nil
  318. }
  319. func (pv *propVirtual) configure(suffix int) error {
  320. if runtime.GOOS == "openbsd" {
  321. pv.name = fmt.Sprintf("vether%d", suffix)
  322. } else {
  323. pv.name = fmt.Sprintf("vlan%d", suffix)
  324. }
  325. xname, err := exec.LookPath("ifconfig")
  326. if err != nil {
  327. return err
  328. }
  329. pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
  330. Path: xname,
  331. Args: []string{"ifconfig", pv.name, "create"},
  332. })
  333. if runtime.GOOS == "netbsd" {
  334. // NetBSD requires an underlying dot1Q-capable network
  335. // interface.
  336. pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
  337. Path: xname,
  338. Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
  339. })
  340. }
  341. pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
  342. Path: xname,
  343. Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask},
  344. })
  345. pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{
  346. Path: xname,
  347. Args: []string{"ifconfig", pv.name, "destroy"},
  348. })
  349. return nil
  350. }