代码拉取完成,页面将自动刷新
package system
import (
"bufio"
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"gitee.com/anesec/mobius/types"
"gitee.com/anesec/mobius/utils"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"io"
"net"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"sync"
)
var (
intfMatcher = regexp.MustCompile(`^(eth|ens|eno|wlp|enp)\d+`)
filters etherFilters
filtersOnce sync.Once
)
func loadFilters() {
filtersOnce.Do(func() {
filters = make(etherFilters, 0, 4)
patterns := strings.Split(os.Getenv(types.NodeEtherPattern), ",")
for _, pattern := range patterns {
pattern = strings.TrimSpace(pattern)
if pattern == "" {
continue
}
if strings.HasPrefix(pattern, "v4:") {
if len(pattern) == 3 {
log.Warnf("Malformed ether name pattern '%s', only contains ip version but no pattern specified", pattern)
continue
}
filters = append(filters, ðerFilter{
pattern: pattern[3:],
flags: ipv4,
})
} else if strings.HasPrefix(pattern, "v6:") {
if len(pattern) == 3 {
log.Warnf("Malformed ether name pattern '%s', only contains ip version but no pattern specified", pattern)
continue
}
filters = append(filters, ðerFilter{
pattern: pattern[3:],
flags: ipv6,
})
} else {
filters = append(filters, ðerFilter{
pattern: pattern,
flags: ipv4 | ipv6,
})
}
}
})
}
const (
ipv4 = 0x1 << iota
ipv6
)
type etherFilter struct {
pattern string
regexp *regexp.Regexp
flags byte
}
func (filter *etherFilter) hasIPv4() bool {
return filter.flags&ipv4 == ipv4
}
func (filter *etherFilter) hasIPv6() bool {
return filter.flags&ipv6 == ipv6
}
func (filter *etherFilter) match(name string) bool {
if filter.regexp == nil {
var err error
if filter.regexp, err = regexp.Compile(filter.pattern); err != nil {
log.Warnf("Malformed ether name pattern '%s', %v", filter.pattern, err)
return false
}
}
return filter.regexp.MatchString(name)
}
func (filter *etherFilter) matchIPv4(name string) bool {
if !filter.hasIPv4() {
return false
}
return filter.match(name)
}
func (filter *etherFilter) matchIPv6(name string) bool {
if !filter.hasIPv6() {
return false
}
return filter.match(name)
}
type etherFilters []*etherFilter
func (filters etherFilters) match(name string) bool {
for _, filter := range filters {
if filter.match(name) {
return true
}
}
return false
}
func (filters etherFilters) matchIPv4(name string) bool {
for _, filter := range filters {
if filter.matchIPv4(name) {
return true
}
}
return false
}
func (filters etherFilters) matchIPv6(name string) bool {
for _, filter := range filters {
if filter.matchIPv6(name) {
return true
}
}
return false
}
func (filters etherFilters) hasIPv4() bool {
for _, filter := range filters {
if filter.hasIPv4() {
return true
}
}
return false
}
func (filters etherFilters) hasIPv6() bool {
for _, filter := range filters {
if filter.hasIPv6() {
return true
}
}
return false
}
const (
none = iota
active
inactive
)
type Network struct {
name string
mac string
v4s []net.IP
v6s []net.IP
flags net.Flags
state int
}
func (network *Network) Name() string {
return network.name
}
func (network *Network) Mac() string {
return network.mac
}
func (network *Network) IPv4() string {
if size := len(network.v4s); size == 0 {
return ""
} else if size == 1 && network.v4s[0] != nil {
return network.v4s[0].String()
}
for _, ip := range network.v4s {
if ip != nil {
return ip.String()
}
}
return ""
}
func (network *Network) IPv4s() []string {
if len(network.v4s) == 0 {
return nil
}
ips := make([]string, 0, len(network.v4s))
for _, ip := range network.v4s {
if ip != nil {
ips = append(ips, ip.String())
}
}
return ips
}
func (network *Network) IPv6() string {
if size := len(network.v6s); size == 0 {
return ""
} else if size == 1 && network.v6s[0] != nil {
return network.v6s[0].String()
}
for _, ip := range network.v6s {
if ip != nil {
return ip.String()
}
}
return ""
}
func (network *Network) IPv6s() []string {
if len(network.v6s) == 0 {
return nil
}
ips := make([]string, 0, len(network.v6s))
for _, ip := range network.v6s {
if ip != nil {
ips = append(ips, ip.String())
}
}
return ips
}
func (network *Network) String() string {
if network.name == "" {
return ""
}
var buf bytes.Buffer
buf.WriteString(network.name)
buf.WriteString(":")
s := network.IPv4()
if s != "" {
buf.WriteString(" inet ")
buf.WriteString(s)
}
s = network.IPv6()
if s != "" {
buf.WriteString(" inet6 ")
buf.WriteString(s)
}
if network.mac != "" {
buf.WriteString(" ether ")
buf.WriteString(network.mac)
}
return buf.String()
}
func (network *Network) IsActive() bool {
if network.state > none {
return network.state == active
}
network.state = active
if (network.flags&net.FlagUp == net.FlagUp) && (network.flags&net.FlagRunning == net.FlagRunning) {
return true
}
buf := utils.Acquire()
defer utils.Recycle(buf)
if err := utils.ReadAll(filepath.Join("/sys/class/net/", network.name, "carrier"), buf); err == nil && strings.TrimSpace(buf.String()) == "0" {
network.state = inactive
return false
}
buf.Reset()
if err := utils.ReadAll(filepath.Join("/sys/class/net/", network.name, "operstate"), buf); err == nil && strings.TrimSpace(buf.String()) == "down" {
network.state = inactive
return false
}
return true
}
func GetNetworks() Networks {
var (
ifaces []net.Interface
addrs []net.Addr
ip net.IP
networks Networks
network *Network
virtuals map[string]struct{}
exists bool
entries []os.DirEntry
links []netlink.Link
err error
)
if entries, err = os.ReadDir("/sys/devices/virtual/net/"); err == nil {
virtuals = make(map[string]struct{}, len(entries))
for _, entry := range entries {
virtuals[entry.Name()] = struct{}{}
}
}
if links, err = netlink.LinkList(); err == nil {
for _, link := range links {
attrs := link.Attrs()
if _, ok := virtuals[attrs.Name]; ok {
switch link.Type() {
case "bond":
delete(virtuals, attrs.Name)
}
}
}
}
loadFilters()
if ifaces, err = net.Interfaces(); err != nil {
log.Errorf("Retrieve host net interfaces failed, %v", err)
return Networks{}
}
networks = make(Networks, 0, len(ifaces))
for _, iface := range ifaces {
if _, exists = virtuals[iface.Name]; exists && !filters.match(iface.Name) {
continue
}
if (iface.Flags & net.FlagUp) == 0 {
// skip if interface down
continue
}
if iface.Flags&net.FlagLoopback != 0 {
// skip loopback interface
continue
}
if addrs, err = iface.Addrs(); err != nil {
continue
}
ip = nil
skipIPv6 := false
for _, addr := range addrs {
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() || ip.IsMulticast() {
continue
}
network, exists = lo.Find(networks, func(item *Network) bool {
return item.name == iface.Name
})
if !exists || network == nil {
network = &Network{name: iface.Name, mac: iface.HardwareAddr.String(), flags: iface.Flags, v4s: make([]net.IP, 0, 2), v6s: make([]net.IP, 0, 2)}
exists = false
}
var v4 net.IP
if v4 = ip.To4(); v4 != nil {
network.v4s = append(network.v4s, v4)
} else if !skipIPv6 && len(ip) == net.IPv6len && (ip.IsPrivate() || ip.IsLinkLocalUnicast()) {
if ip.IsPrivate() {
skipIPv6 = true
}
network.v6s = append(network.v6s, ip)
}
if exists || (len(network.v4s) == 0 && len(network.v6s) == 0) {
continue
}
networks = append(networks, network)
}
}
return networks
}
type Networks []*Network
func (networks Networks) Len() int {
return len(networks)
}
func (networks Networks) String() string {
var (
data []byte
err error
)
if networks.Len() == 0 {
return ""
}
list := make([]map[string]string, 0, len(networks))
for _, addr := range networks {
v4 := addr.IPv4()
v6 := addr.IPv6()
if v4 == "" && v6 == "" {
continue
}
list = append(list, map[string]string{
"Name": addr.Name(),
"Mac": addr.Mac(),
"IPv4": v4,
"IPv4s": strings.Join(addr.IPv4s(), ","),
"IPv6": v6,
"IPv6s": strings.Join(addr.IPv6s(), ","),
})
}
if data, err = json.Marshal(list); err != nil {
log.Errorf("Retrieve host ip list failed, %v", err)
return ""
}
return string(data)
}
func (networks Networks) First() *Network {
if networks.Len() == 0 || (networks[0].v4s == nil && networks[0].v6s == nil) {
return &Network{}
}
if item, ok := lo.Find(networks, func(item *Network) bool {
return item.IsActive() && (item.v4s != nil || item.v6s != nil)
}); ok && item != nil {
return item
}
return networks[0]
}
func (networks Networks) IPv4() string {
if networks.Len() == 0 {
return ""
}
// check user specified ether address first
for index := range networks {
if filters.matchIPv4(networks[index].Name()) {
if v4 := networks[index].IPv4(); v4 != "" {
return v4
}
}
}
// user specify ipv4 ether name pattern, but not found
if filters.hasIPv4() {
return ""
}
for index := range networks {
// For QAX, show eth1's ip if existed, but not a good way to do this?
if networks[index].Name() == "eth1" && networks[index].IsActive() {
if v4 := networks[index].IPv4(); v4 != "" {
return v4
}
}
}
if item, ok := lo.Find(networks, func(item *Network) bool {
return item.IsActive() && item.v4s != nil
}); ok && item != nil {
if v4 := item.IPv4(); v4 != "" {
return v4
}
}
for index := range networks {
if intfMatcher.MatchString(networks[index].Name()) && networks[index].IsActive() {
if v4 := networks[index].IPv4(); v4 != "" {
return v4
}
}
}
for index := range networks {
if v4 := networks[index].IPv4(); v4 != "" {
return v4
}
}
return ""
}
func (networks Networks) IPv6() string {
if networks.Len() == 0 {
return ""
}
// check user specified ether address first
for index := range networks {
if filters.matchIPv6(networks[index].Name()) {
if v6 := networks[index].IPv6(); v6 != "" {
return v6
}
}
}
// user specify ipv6 ether name pattern, but not found
if filters.hasIPv6() {
return ""
}
for index := range networks {
// For QAX, show eth1's ip if existed, but not a good way to do this?
if networks[index].Name() == "eth1" && networks[index].IsActive() {
if v6 := networks[index].IPv6(); v6 != "" {
return v6
}
}
}
if item, ok := lo.Find(networks, func(item *Network) bool {
return item.IsActive() && item.v6s != nil
}); ok && item != nil {
if v6 := item.IPv6(); v6 != "" {
return v6
}
}
for index := range networks {
if intfMatcher.MatchString(networks[index].Name()) && networks[index].IsActive() {
if v6 := networks[index].IPv6(); v6 != "" {
return v6
}
}
}
for index := range networks {
if v6 := networks[index].IPv6(); v6 != "" {
return v6
}
}
return ""
}
func Bridges(ctx context.Context) ([]*net.IPNet, error) {
var (
stdout bytes.Buffer
stderr bytes.Buffer
data []byte
err error
)
cmd := exec.CommandContext(ctx, "ip", "address", "show", "type", "bridge")
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err = cmd.Run(); err != nil {
if stderr.Len() > 0 {
err = fmt.Errorf("%v, %s", err, stderr.String())
}
return nil, err
}
if stderr.Len() > 0 {
return nil, errors.New(stderr.String())
}
nets := make([]*net.IPNet, 0, bytes.Count(stdout.Bytes(), []byte{'\n'}))
br := bufio.NewReader(&stdout)
for {
if data, _, err = br.ReadLine(); err != nil {
if errors.Is(err, io.EOF) {
err = nil
}
break
}
fields := strings.Fields(strings.TrimSpace(string(data)))
switch fields[0] {
case "inet", "inet6":
if _, _net, err := net.ParseCIDR(fields[1]); err == nil {
nets = append(nets, _net)
}
}
}
return nets, err
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。