2018-06-28 20:08:23 +02:00

86 lines
1.9 KiB
Go

// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package diag
import (
"fmt"
"net"
)
type ra6 struct {
children []Node
ifname string
}
func (d *ra6) String() string {
return "ra6/" + d.ifname
}
func (d *ra6) Then(t Node) Node {
d.children = append(d.children, t)
return d
}
func (d *ra6) Children() []Node {
return d.children
}
func isEUI64(ip net.IP) bool {
if ip.To16() == nil {
return false
}
ip = ip.To16()
return ip[11] == 0xff && ip[12] == 0xfe
}
func (d *ra6) Evaluate() (string, error) {
iface, err := net.InterfaceByName(d.ifname)
if err != nil {
return "", err
}
addrs, err := iface.Addrs()
if err != nil {
return "", err
}
var first string
for _, addr := range addrs {
ipnet, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ones, _ := ipnet.Mask.Size(); ones != 64 {
continue
}
if !global.Contains(ipnet.IP) {
continue // skip local IPv6 addresses
}
if !isEUI64(ipnet.IP) {
continue // skip non-autoconf addresses (e.g. DHCPv6 temporary IP)
}
first = ipnet.String()
}
if first == "" {
return "", fmt.Errorf("no SLAAC address found")
}
return first, nil
}
// RouterAdvertisments returns a Node which succeeds if the specified interface
// obtained at least one address from IPv6 router advertisments.
func RouterAdvertisments(ifname string) Node {
return &ra6{ifname: ifname}
}