package cmd import ( "fmt" "net" "regexp" "strconv" "strings" "io/ioutil" "golang.org/x/net/route" ) var defaultRoute4 = [4]byte{0, 0, 0, 0} var defaultRoute6 = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} var local6 = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} func Inet4AddrToString(ip4 route.Inet4Addr) string { return fmt.Sprintf("%v.%v.%v.%v", ip4.IP[0], ip4.IP[1], ip4.IP[2], ip4.IP[3]) } func Inet6AddrToString(ip6 route.Inet6Addr) string { return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", ip6.IP[0], ip6.IP[1], ip6.IP[2], ip6.IP[3], ip6.IP[4], ip6.IP[5], ip6.IP[6], ip6.IP[7], ip6.IP[8], ip6.IP[9], ip6.IP[10], ip6.IP[11], ip6.IP[12], ip6.IP[13], ip6.IP[14], ip6.IP[15]) } /***************************************************************************** * Initialize default_interface, default_gatway4, default_gateway6 *****************************************************************************/ func (jh *JailHost) InitNetworkProperties() { rib, _ := route.FetchRIB(0, route.RIBTypeRoute, 0) messages, err := route.ParseRIB(route.RIBTypeRoute, rib) if err != nil { panic(err) } for _, message := range messages { route_message := message.(*route.RouteMessage) addresses := route_message.Addrs card_index := route_message.Index if addresses[0].Family() == 2 { var destination4, gateway4 *route.Inet4Addr ok := false if destination4, ok = addresses[0].(*route.Inet4Addr); !ok { continue } if gateway4, ok = addresses[1].(*route.Inet4Addr); !ok { continue } if destination4 == nil || gateway4 == nil { continue } if destination4.IP == defaultRoute4 { card, _ := net.InterfaceByIndex(card_index) //fmt.Printf("Default IPv4 gateway is %v on card %s\n", Inet4AddrToString(*gateway4), card.Name) jh.default_interface = card.Name jh.default_gateway4 = Inet4AddrToString(*gateway4) } } else if addresses[0].Family() == 28 { var destination6, gateway6 *route.Inet6Addr ok := false if destination6, ok = addresses[0].(*route.Inet6Addr); !ok { continue } if gateway6, ok = addresses[1].(*route.Inet6Addr); !ok { continue } if destination6 == nil || gateway6 == nil { continue } if destination6.IP == defaultRoute6 && gateway6.IP != local6 { card, _ := net.InterfaceByIndex(card_index) //fmt.Printf("Default IPv6 gateway is %v on card %s\n", Inet6AddrToString(*gateway6), card.Name) jh.default_interface = card.Name jh.default_gateway6 = Inet6AddrToString(*gateway6) } } } } func (jh *JailHost) GetDefaultInterface() string { if len(jh.default_interface) == 0 { jh.InitNetworkProperties() } return jh.default_interface } func (jh *JailHost) GetDefaultGateway4() string { if len(jh.default_gateway4) == 0 { jh.InitNetworkProperties() } return jh.default_gateway4 } func (jh *JailHost) GetDefaultGateway6() string { if len(jh.default_gateway6) == 0 { jh.InitNetworkProperties() } return jh.default_gateway6 } /***************************************************************************** * Get all network interfaces ****************************************************************************/ func (jh *JailHost) GetInterfaces() ([]string, error) { var names []string interfaces, err := net.Interfaces() if err != nil { return names, fmt.Errorf("Error listing network interfaces: %v", err) } for _, n := range interfaces { names = append(names, n.Name) } return names, nil } func (jh *JailHost) GetBridgeMTU(bridgeName string) (int, error) { bridge, err := net.InterfaceByName(bridgeName) if err != nil { return 0, err } return bridge.MTU, nil } /***************************************************************************** * Get all IPv4 currently in use on host ****************************************************************************/ func getHostInUseIPv4() ([]string, error) { var ips []string re := regexp.MustCompile(ifconfigipv4re) out, err := executeCommand("/sbin/ifconfig") if err != nil { return ips, fmt.Errorf("Error executing \"/sbin/ifconfig\": %s", err) } for _, line := range strings.Split(out, "\n") { if re.MatchString(line) { ips = append(ips, re.FindStringSubmatch(line)[1]) } } return ips, nil } func getHostname() (string, error) { out, err := executeCommand("/bin/hostname") if err != nil { return "", fmt.Errorf("Error executing \"/bin/hostname\": %v", err) } return strings.Split(out, "\n")[0], nil } func getHostId() (string, error) { var content []byte var err error // return empty string if file does not exist if content, err = ioutil.ReadFile("/etc/hostid"); err != nil { if strings.HasSuffix(err.Error(), "no such file or directory") { return "", nil } return "", err } return strings.Split(string(content), "\n")[0], nil } func getFreeBSDVersion() (FreeBSDVersion, error) { var version FreeBSDVersion regex := `([0-9]{1,2})(\.)?([0-9]{1,2})?\-([^\-]*)(\-)?(p[0-9]{1,2})?` re := regexp.MustCompile(regex) out, err := executeCommand("/bin/freebsd-version") if err != nil { return version, fmt.Errorf("Error executing \"/bin/freebsd-version\": %v", err) } if re.MatchString(out) { version.major, err = strconv.Atoi(re.FindStringSubmatch(out)[1]) if err != nil { return version, err } version.minor, err = strconv.Atoi(re.FindStringSubmatch(out)[3]) if err != nil { return version, err } version.flavor = strings.Trim(re.FindStringSubmatch(out)[4], "\n") // Skip the 'p' starting patch level if len(re.FindStringSubmatch(out)[6]) > 0 { version.patchLevel, err = strconv.Atoi(re.FindStringSubmatch(out)[6][1:]) if err != nil { return version, err } } } return version, nil } func NewJailHost() (JailHost, error) { var jh JailHost var err error if jh.hostname, err = getHostname(); err != nil { return jh, err } if jh.hostid, err = getHostId(); err != nil { return jh, err } if jh.version, err = getFreeBSDVersion(); err != nil { return jh, err } return jh, nil }