ing
This commit is contained in:
		
							parent
							
								
									df86e3cf66
								
							
						
					
					
						commit
						b88509516a
					
				@ -76,3 +76,11 @@
 | 
			
		||||
[prune]
 | 
			
		||||
  go-tests = true
 | 
			
		||||
  unused-packages = true
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "github.com/grandcat/zeroconf"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "github.com/huin/goupnp"
 | 
			
		||||
 | 
			
		||||
@ -18,22 +18,28 @@ var (
 | 
			
		||||
		ExcludePatterns: []string{},
 | 
			
		||||
	}
 | 
			
		||||
	z = &omd.Zone{
 | 
			
		||||
		Network:    "192.168.1.0/24",
 | 
			
		||||
		Network:    "192.168.35.0/24",
 | 
			
		||||
		MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
 | 
			
		||||
		Address:    "192.168.1.201",
 | 
			
		||||
		Iface:      "\\Device\\NPF_{1924FA2B-6927-4BA5-AF43-876C3F8853CE}",
 | 
			
		||||
		Mac:        "30:9C:23:15:A3:09",
 | 
			
		||||
		// Address:    "192.168.1.201",
 | 
			
		||||
		// Iface:      "\\Device\\NPF_{1924FA2B-6927-4BA5-AF43-876C3F8853CE}",
 | 
			
		||||
		// Mac:        "30:9C:23:15:A3:09",
 | 
			
		||||
		// Address: "192.168.1.101",
 | 
			
		||||
		// Iface:   "enp3s0",
 | 
			
		||||
		// Mac:     "44:8a:5b:f1:f1:f3",
 | 
			
		||||
		Address: "192.168.35.234",
 | 
			
		||||
		Iface:   "wlp5s0",
 | 
			
		||||
		Mac:     "d0:7e:35:da:26:68",
 | 
			
		||||
	}
 | 
			
		||||
	dh = &omd.DiscoverHost{
 | 
			
		||||
		MetaIPType:     omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
 | 
			
		||||
		FirstScanRange: "192.168.1.1",
 | 
			
		||||
		LastScanRange:  "192.168.1.254",
 | 
			
		||||
		FirstScanRange: "192.168.35.1",
 | 
			
		||||
		LastScanRange:  "192.168.35.254",
 | 
			
		||||
	}
 | 
			
		||||
	h = &omd.Host{
 | 
			
		||||
		Zone:       z,
 | 
			
		||||
		MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
 | 
			
		||||
		Address:    "127.0.0.1",
 | 
			
		||||
		Mac:        "50:E5:49:46:93:28",
 | 
			
		||||
		Address:    "192.168.35.80",
 | 
			
		||||
		Mac:        "6c:ad:f8:d3:f8:c6",
 | 
			
		||||
	}
 | 
			
		||||
	dp = &omd.DiscoverPort{
 | 
			
		||||
		FirstScanRange: 1,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										266
									
								
								mdns/mdns.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								mdns/mdns.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,266 @@
 | 
			
		||||
package mdns
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	omd "git.loafle.net/overflow/model/discovery"
 | 
			
		||||
	omm "git.loafle.net/overflow/model/meta"
 | 
			
		||||
	omu "git.loafle.net/overflow/model/util"
 | 
			
		||||
	"git.loafle.net/overflow_scanner/probe/model"
 | 
			
		||||
	"github.com/grandcat/zeroconf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type serviceMeta struct {
 | 
			
		||||
	name       string
 | 
			
		||||
	cryptoType string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	serviceMetaMapping = map[string]*serviceMeta{
 | 
			
		||||
		"http": &serviceMeta{
 | 
			
		||||
			name:       "HTTP",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"printer": &serviceMeta{
 | 
			
		||||
			name:       "PRINTER",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"pdl-datastream": &serviceMeta{
 | 
			
		||||
			name:       "PDL-DATASTREAM",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"ipp": &serviceMeta{
 | 
			
		||||
			name:       "IPP",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"webdav": &serviceMeta{
 | 
			
		||||
			name:       "WEBDAV",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"webdavs": &serviceMeta{
 | 
			
		||||
			name:       "WEBDAV",
 | 
			
		||||
			cryptoType: "TLS",
 | 
			
		||||
		},
 | 
			
		||||
		"afpovertcp": &serviceMeta{
 | 
			
		||||
			name:       "AFP",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"smb": &serviceMeta{
 | 
			
		||||
			name:       "SMB",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
		"rfb": &serviceMeta{
 | 
			
		||||
			name:       "RFB",
 | 
			
		||||
			cryptoType: "NONE",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Scan(discovered model.Discovered) {
 | 
			
		||||
	serviceEntries, err := browse("_services._dns-sd._udp", "local")
 | 
			
		||||
	if nil != err {
 | 
			
		||||
		log.Print("Cannot find service ", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	metaIPTypeEnum := omm.ToMetaIPTypeEnum(discovered.Zone().MetaIPType)
 | 
			
		||||
 | 
			
		||||
	for _, serviceEntry := range serviceEntries {
 | 
			
		||||
		name := removeDomainName(serviceEntry.Instance, serviceEntry.Domain)
 | 
			
		||||
		entries, _err := browse(name, serviceEntry.Domain)
 | 
			
		||||
		if nil != _err {
 | 
			
		||||
			log.Print("Cannot find entry ", _err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	LOOP:
 | 
			
		||||
		for _, entry := range entries {
 | 
			
		||||
			log.Print("serviceEntry ", entry)
 | 
			
		||||
 | 
			
		||||
			name := entry.Instance   // HP\ LaserJet\ P1505n
 | 
			
		||||
			service := entry.Service // _pdl-datastream._tcp
 | 
			
		||||
			port := entry.Port       // 9100
 | 
			
		||||
			meta := toMeta(entry.Text)
 | 
			
		||||
			hostName := removeDomainName(entry.HostName, entry.Domain) // NPIFACA9B
 | 
			
		||||
			serviceName, portType, cryptoType := parseService(service)
 | 
			
		||||
 | 
			
		||||
			var metaPortType *omm.MetaPortType
 | 
			
		||||
			switch portType {
 | 
			
		||||
			case "tcp":
 | 
			
		||||
				metaPortType = omm.ToMetaPortType(omm.MetaPortTypeEnumTCP)
 | 
			
		||||
			case "udp":
 | 
			
		||||
				metaPortType = omm.ToMetaPortType(omm.MetaPortTypeEnumUDP)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			metaCryptoType := omm.ToMetaCryptoType(omm.MetaCryptoTypeEnumUNKNOWN)
 | 
			
		||||
			switch cryptoType {
 | 
			
		||||
			case "NONE":
 | 
			
		||||
				metaCryptoType = omm.ToMetaCryptoType(omm.MetaCryptoTypeEnumNONE)
 | 
			
		||||
			case "TLS":
 | 
			
		||||
				metaCryptoType = omm.ToMetaCryptoType(omm.MetaCryptoTypeEnumTLS)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			switch metaIPTypeEnum {
 | 
			
		||||
			case omm.MetaIPTypeEnumV4:
 | 
			
		||||
				for _, ipv4 := range entry.AddrIPv4 {
 | 
			
		||||
					h := discovered.AddHost(&omd.Host{
 | 
			
		||||
						MetaIPType:     omm.ToMetaIPType(metaIPTypeEnum),
 | 
			
		||||
						Name:           hostName,
 | 
			
		||||
						Address:        ipv4.String(),
 | 
			
		||||
						Meta:           meta,
 | 
			
		||||
						Zone:           discovered.Zone(),
 | 
			
		||||
						DiscoveredDate: omu.NowPtr(),
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
					if 1 > port {
 | 
			
		||||
						continue LOOP
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					p := discovered.AddPort(&omd.Port{
 | 
			
		||||
						MetaPortType: metaPortType,
 | 
			
		||||
						PortNumber:   json.Number(strconv.Itoa(port)),
 | 
			
		||||
						Meta:         meta,
 | 
			
		||||
						Host:         h,
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
					discovered.AddService(&omd.Service{
 | 
			
		||||
						MetaCryptoType: metaCryptoType,
 | 
			
		||||
						Key:            serviceName,
 | 
			
		||||
						Name:           name,
 | 
			
		||||
						Port:           p,
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			case omm.MetaIPTypeEnumV6:
 | 
			
		||||
				for _, ipv6 := range entry.AddrIPv6 {
 | 
			
		||||
					h := discovered.AddHost(&omd.Host{
 | 
			
		||||
						MetaIPType:     omm.ToMetaIPType(metaIPTypeEnum),
 | 
			
		||||
						Name:           hostName,
 | 
			
		||||
						Address:        ipv6.String(),
 | 
			
		||||
						Meta:           meta,
 | 
			
		||||
						Zone:           discovered.Zone(),
 | 
			
		||||
						DiscoveredDate: omu.NowPtr(),
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
					if 1 > port {
 | 
			
		||||
						continue LOOP
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					p := discovered.AddPort(&omd.Port{
 | 
			
		||||
						MetaPortType: metaPortType,
 | 
			
		||||
						PortNumber:   json.Number(strconv.Itoa(port)),
 | 
			
		||||
						Meta:         meta,
 | 
			
		||||
						Host:         h,
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
					discovered.AddService(&omd.Service{
 | 
			
		||||
						MetaCryptoType: metaCryptoType,
 | 
			
		||||
						Key:            serviceName,
 | 
			
		||||
						Name:           name,
 | 
			
		||||
						Port:           p,
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeDomainName(instance string, domain string) (service string) {
 | 
			
		||||
	_instance := strings.TrimRight(instance, ".")
 | 
			
		||||
	return strings.TrimRight(_instance, fmt.Sprintf(".%s", domain))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toMeta(text []string) map[string]string {
 | 
			
		||||
	if nil == text || 0 == len(text) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	meta := make(map[string]string)
 | 
			
		||||
	for _, v := range text {
 | 
			
		||||
		ss := strings.SplitN(v, "=", 2)
 | 
			
		||||
		if 2 != len(ss) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if nil != ss {
 | 
			
		||||
			meta[ss[0]] = ss[1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return meta
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseService(service string) (name string, portType string, cryptoType string) {
 | 
			
		||||
	ss := strings.SplitN(service, ".", 2)
 | 
			
		||||
	if nil == ss {
 | 
			
		||||
		return "UNKNOWN", "UNKNOWN", "UNKNOWN"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_name := strings.TrimLeft(ss[0], "_")
 | 
			
		||||
	_portType := strings.TrimLeft(ss[1], "_")
 | 
			
		||||
 | 
			
		||||
	m, ok := serviceMetaMapping[_name]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return "UNKNOWN", "UNKNOWN", "UNKNOWN"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name = m.name
 | 
			
		||||
	portType = _portType
 | 
			
		||||
	cryptoType = m.cryptoType
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func browse(service string, domain string) ([]*zeroconf.ServiceEntry, error) {
 | 
			
		||||
	resolver, err := zeroconf.NewResolver(nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Failed to initialize resolver %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	entryChan := make(chan *zeroconf.ServiceEntry)
 | 
			
		||||
	timerStopped := make(chan struct{})
 | 
			
		||||
 | 
			
		||||
	serviceEntries := make([]*zeroconf.ServiceEntry, 0)
 | 
			
		||||
 | 
			
		||||
	go func(_entryChan <-chan *zeroconf.ServiceEntry) {
 | 
			
		||||
		var delay atomic.Value
 | 
			
		||||
		delay.Store(false)
 | 
			
		||||
		ticker := time.NewTicker(time.Second * 1)
 | 
			
		||||
 | 
			
		||||
		for {
 | 
			
		||||
			select {
 | 
			
		||||
			case entry, ok := <-_entryChan:
 | 
			
		||||
				if !ok {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				delay.Store(true)
 | 
			
		||||
				serviceEntries = append(serviceEntries, entry)
 | 
			
		||||
			case <-ticker.C:
 | 
			
		||||
				if false == delay.Load().(bool) {
 | 
			
		||||
					ticker.Stop()
 | 
			
		||||
					timerStopped <- struct{}{}
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				delay.Store(false)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}(entryChan)
 | 
			
		||||
 | 
			
		||||
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(30))
 | 
			
		||||
	defer cancel()
 | 
			
		||||
	err = resolver.Browse(ctx, service, domain, entryChan)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Failed to browse %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
	case <-timerStopped:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return serviceEntries, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										139
									
								
								mdns/mdns_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								mdns/mdns_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
package mdns
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	omd "git.loafle.net/overflow/model/discovery"
 | 
			
		||||
	omm "git.loafle.net/overflow/model/meta"
 | 
			
		||||
	"git.loafle.net/overflow_scanner/probe/model"
 | 
			
		||||
	"github.com/grandcat/zeroconf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestScan(t *testing.T) {
 | 
			
		||||
	type args struct {
 | 
			
		||||
		discovered model.Discovered
 | 
			
		||||
	}
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name string
 | 
			
		||||
		args args
 | 
			
		||||
	}{
 | 
			
		||||
		// TODO: Add test cases.
 | 
			
		||||
		{
 | 
			
		||||
			name: "1",
 | 
			
		||||
			args: args{
 | 
			
		||||
				discovered: model.New(
 | 
			
		||||
					&omd.Zone{
 | 
			
		||||
						Network:    "192.168.1.0/24",
 | 
			
		||||
						Iface:      "enp3s0",
 | 
			
		||||
						MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
 | 
			
		||||
						Address:    "192.168.1.101",
 | 
			
		||||
						Mac:        "44:8a:5b:f1:f1:f3",
 | 
			
		||||
					},
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			Scan(tt.args.discovered)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_removeDomainName(t *testing.T) {
 | 
			
		||||
	type args struct {
 | 
			
		||||
		instance string
 | 
			
		||||
		domain   string
 | 
			
		||||
	}
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		args        args
 | 
			
		||||
		wantService string
 | 
			
		||||
	}{
 | 
			
		||||
		// TODO: Add test cases.
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			if gotService := removeDomainName(tt.args.instance, tt.args.domain); gotService != tt.wantService {
 | 
			
		||||
				t.Errorf("removeDomainName() = %v, want %v", gotService, tt.wantService)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_toMeta(t *testing.T) {
 | 
			
		||||
	type args struct {
 | 
			
		||||
		text []string
 | 
			
		||||
	}
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name string
 | 
			
		||||
		args args
 | 
			
		||||
		want map[string]string
 | 
			
		||||
	}{
 | 
			
		||||
		// TODO: Add test cases.
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			if got := toMeta(tt.args.text); !reflect.DeepEqual(got, tt.want) {
 | 
			
		||||
				t.Errorf("toMeta() = %v, want %v", got, tt.want)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_parseService(t *testing.T) {
 | 
			
		||||
	type args struct {
 | 
			
		||||
		service string
 | 
			
		||||
	}
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name           string
 | 
			
		||||
		args           args
 | 
			
		||||
		wantName       string
 | 
			
		||||
		wantPortType   string
 | 
			
		||||
		wantCryptoType string
 | 
			
		||||
	}{
 | 
			
		||||
		// TODO: Add test cases.
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			gotName, gotPortType, gotCryptoType := parseService(tt.args.service)
 | 
			
		||||
			if gotName != tt.wantName {
 | 
			
		||||
				t.Errorf("parseService() gotName = %v, want %v", gotName, tt.wantName)
 | 
			
		||||
			}
 | 
			
		||||
			if gotPortType != tt.wantPortType {
 | 
			
		||||
				t.Errorf("parseService() gotPortType = %v, want %v", gotPortType, tt.wantPortType)
 | 
			
		||||
			}
 | 
			
		||||
			if gotCryptoType != tt.wantCryptoType {
 | 
			
		||||
				t.Errorf("parseService() gotCryptoType = %v, want %v", gotCryptoType, tt.wantCryptoType)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_browse(t *testing.T) {
 | 
			
		||||
	type args struct {
 | 
			
		||||
		service string
 | 
			
		||||
		domain  string
 | 
			
		||||
	}
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name    string
 | 
			
		||||
		args    args
 | 
			
		||||
		want    []*zeroconf.ServiceEntry
 | 
			
		||||
		wantErr bool
 | 
			
		||||
	}{
 | 
			
		||||
		// TODO: Add test cases.
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			got, err := browse(tt.args.service, tt.args.domain)
 | 
			
		||||
			if (err != nil) != tt.wantErr {
 | 
			
		||||
				t.Errorf("browse() error = %v, wantErr %v", err, tt.wantErr)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if !reflect.DeepEqual(got, tt.want) {
 | 
			
		||||
				t.Errorf("browse() = %v, want %v", got, tt.want)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										178
									
								
								model/Discovered.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								model/Discovered.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,178 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	omd "git.loafle.net/overflow/model/discovery"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Discovered interface {
 | 
			
		||||
	Zone() *omd.Zone
 | 
			
		||||
	AddHost(host *omd.Host) *omd.Host
 | 
			
		||||
	AddPort(port *omd.Port) *omd.Port
 | 
			
		||||
	AddService(service *omd.Service) *omd.Service
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(zone *omd.Zone) Discovered {
 | 
			
		||||
	return &discovered{
 | 
			
		||||
		zone:     zone,
 | 
			
		||||
		hosts:    make(map[string]*omd.Host),
 | 
			
		||||
		ports:    make(map[*omd.Host]map[json.Number]map[string]*omd.Port),
 | 
			
		||||
		services: make(map[*omd.Port]map[string]map[string]*omd.Service),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type discovered struct {
 | 
			
		||||
	zone     *omd.Zone
 | 
			
		||||
	hosts    map[string]*omd.Host
 | 
			
		||||
	ports    map[*omd.Host]map[json.Number]map[string]*omd.Port
 | 
			
		||||
	services map[*omd.Port]map[string]map[string]*omd.Service
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) Zone() *omd.Zone {
 | 
			
		||||
	return d.zone
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) AddHost(host *omd.Host) *omd.Host {
 | 
			
		||||
	h := d.findHost(host, true)
 | 
			
		||||
 | 
			
		||||
	if "" == h.Mac && "" != host.Mac {
 | 
			
		||||
		h.Mac = host.Mac
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h.Meta = d.appendMeta(h.Meta, host.Meta)
 | 
			
		||||
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) AddPort(port *omd.Port) *omd.Port {
 | 
			
		||||
	p := d.findPort(port, true)
 | 
			
		||||
 | 
			
		||||
	p.Meta = d.appendMeta(p.Meta, port.Meta)
 | 
			
		||||
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) AddService(service *omd.Service) *omd.Service {
 | 
			
		||||
	s := d.findService(service, true)
 | 
			
		||||
 | 
			
		||||
	s.Meta = d.appendMeta(s.Meta, service.Meta)
 | 
			
		||||
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) findHost(host *omd.Host, add bool) *omd.Host {
 | 
			
		||||
	h, ok := d.hosts[host.Address]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		d.hosts[host.Address] = host
 | 
			
		||||
		h = host
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) findPort(port *omd.Port, add bool) *omd.Port {
 | 
			
		||||
	h := d.findHost(port.Host, false)
 | 
			
		||||
	if nil == h {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hostPorts, ok := d.ports[h]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		d.ports[h] = make(map[json.Number]map[string]*omd.Port)
 | 
			
		||||
		hostPorts = d.ports[h]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ports, ok := hostPorts[port.PortNumber]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		hostPorts[port.PortNumber] = make(map[string]*omd.Port)
 | 
			
		||||
		ports = hostPorts[port.PortNumber]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p, ok := ports[port.MetaPortType.Key]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ports[port.MetaPortType.Key] = port
 | 
			
		||||
		p = ports[port.MetaPortType.Key]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) findService(service *omd.Service, add bool) *omd.Service {
 | 
			
		||||
	p := d.findPort(service.Port, false)
 | 
			
		||||
	if nil == p {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	portServices, ok := d.services[p]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		d.services[p] = make(map[string]map[string]*omd.Service)
 | 
			
		||||
		portServices = d.services[p]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	services, ok := portServices[service.Key]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		portServices[service.Key] = make(map[string]*omd.Service)
 | 
			
		||||
		services = portServices[service.Key]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s, ok := services[service.MetaCryptoType.Key]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		if !add {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		services[service.MetaCryptoType.Key] = service
 | 
			
		||||
		s = services[service.MetaCryptoType.Key]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discovered) appendMeta(oriMeta map[string]string, newMeta map[string]string) map[string]string {
 | 
			
		||||
	if nil == newMeta {
 | 
			
		||||
		return oriMeta
 | 
			
		||||
	}
 | 
			
		||||
	if nil == oriMeta {
 | 
			
		||||
		return newMeta
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
LOOP:
 | 
			
		||||
	for k, v := range oriMeta {
 | 
			
		||||
		_v, _ok := oriMeta[k]
 | 
			
		||||
		if !_ok {
 | 
			
		||||
			oriMeta[k] = v
 | 
			
		||||
			continue LOOP
 | 
			
		||||
		}
 | 
			
		||||
		if v == _v {
 | 
			
		||||
			continue LOOP
 | 
			
		||||
		}
 | 
			
		||||
		oriMeta[k] = fmt.Sprintf("%s|||%s", _v, v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return oriMeta
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +1,13 @@
 | 
			
		||||
package service
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	oa "git.loafle.net/overflow/annotation-go"
 | 
			
		||||
	od "git.loafle.net/overflow/di-go"
 | 
			
		||||
	omd "git.loafle.net/overflow/model/discovery"
 | 
			
		||||
	"git.loafle.net/overflow_scanner/probe/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
@ -17,7 +20,9 @@ type DiscoveryService struct {
 | 
			
		||||
	oa.TypeAnnotation `annotation:"@Injectable('name': 'DiscoveryService') @Service()"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *DiscoveryService) StartDiscover() error {
 | 
			
		||||
func (s *DiscoveryService) StartDiscover(zone *omd.Zone) error {
 | 
			
		||||
	d := model.New(zone)
 | 
			
		||||
	log.Print(d)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								upnp/upnp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								upnp/upnp.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
package upnp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	omd "git.loafle.net/overflow/model/discovery"
 | 
			
		||||
	omu "git.loafle.net/overflow/model/util"
 | 
			
		||||
	"git.loafle.net/overflow_scanner/probe/model"
 | 
			
		||||
	"github.com/huin/goupnp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TargetRootDevice = "upnp:rootdevice"
 | 
			
		||||
	TargetSSDPAll    = "ssdp:all"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Scan(discovered model.Discovered) {
 | 
			
		||||
	devs, err := goupnp.DiscoverDevices(TargetRootDevice)
 | 
			
		||||
	if nil != err {
 | 
			
		||||
		fmt.Println("DeletePortMapping: ", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
LOOP:
 | 
			
		||||
	for _, dev := range devs {
 | 
			
		||||
		rd := dev.Root.Device
 | 
			
		||||
		if !rd.PresentationURL.Ok {
 | 
			
		||||
			continue LOOP
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		discovered.AddHost(&omd.Host{
 | 
			
		||||
			MetaIPType: discovered.Zone().MetaIPType,
 | 
			
		||||
			Name:       rd.FriendlyName,
 | 
			
		||||
			Address:    rd.PresentationURL.URL.Host,
 | 
			
		||||
			Meta: map[string]string{
 | 
			
		||||
				"DeviceType":       rd.DeviceType,
 | 
			
		||||
				"Manufacturer":     rd.Manufacturer,
 | 
			
		||||
				"ManufacturerURL":  rd.ManufacturerURL.Str,
 | 
			
		||||
				"ModelName":        rd.ModelName,
 | 
			
		||||
				"ModelDescription": rd.ModelDescription,
 | 
			
		||||
				"ModelNumber":      rd.ModelNumber,
 | 
			
		||||
				"SerialNumber":     rd.SerialNumber,
 | 
			
		||||
				"UDN":              rd.UDN,
 | 
			
		||||
				"UPC":              rd.UPC,
 | 
			
		||||
			},
 | 
			
		||||
			Zone:           discovered.Zone(),
 | 
			
		||||
			DiscoveredDate: omu.NowPtr(),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								upnp/upnp_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								upnp/upnp_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
package upnp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	omd "git.loafle.net/overflow/model/discovery"
 | 
			
		||||
	omm "git.loafle.net/overflow/model/meta"
 | 
			
		||||
	"git.loafle.net/overflow_scanner/probe/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestScan(t *testing.T) {
 | 
			
		||||
	type args struct {
 | 
			
		||||
		discovered model.Discovered
 | 
			
		||||
	}
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name string
 | 
			
		||||
		args args
 | 
			
		||||
	}{
 | 
			
		||||
		// TODO: Add test cases.
 | 
			
		||||
		{
 | 
			
		||||
			name: "1",
 | 
			
		||||
			args: args{
 | 
			
		||||
				discovered: model.New(
 | 
			
		||||
					&omd.Zone{
 | 
			
		||||
						Network:    "192.168.1.0/24",
 | 
			
		||||
						Iface:      "enp3s0",
 | 
			
		||||
						MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
 | 
			
		||||
						Address:    "192.168.1.101",
 | 
			
		||||
						Mac:        "44:8a:5b:f1:f1:f3",
 | 
			
		||||
					},
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			Scan(tt.args.discovered)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user