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.

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