package upnp import ( "fmt" "strconv" "strings" omd "git.loafle.net/overflow/model/discovery" omm "git.loafle.net/overflow/model/meta" omu "git.loafle.net/overflow/model/util" oun "git.loafle.net/overflow/util-go/net" "git.loafle.net/overflow_scanner/probe/discovery/session" "github.com/huin/goupnp" ) const ( TargetRootDevice = "upnp:rootdevice" TargetSSDPAll = "ssdp:all" ) var ( deviceTypes = map[string]omm.MetaHostTypeEnum{ "urn:schemas-upnp-org:device:InternetGatewayDevice:1": omm.MetaHostTypeEnumRouter, "urn:schemas-upnp-org:device:InternetGatewayDevice:2": omm.MetaHostTypeEnumRouter, "urn:schemas-upnp-org:device:WLANAccessPointDevice:1": omm.MetaHostTypeEnumWLANAccessPoint, "urn:schemas-upnp-org:device:MediaServer:1": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaRenderer:1": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaServer:2": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaRenderer:2": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaServer:3": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaRenderer:3": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaServer:4": omm.MetaHostTypeEnumMediaServer, "urn:schemas-upnp-org:device:MediaRenderer:4": omm.MetaHostTypeEnumMediaServer, "urn:dial-multiscreen-org:device:dial:1": omm.MetaHostTypeEnumMultiScreen, "urn:dial-multiscreen-org:device:dial:2": omm.MetaHostTypeEnumMultiScreen, "urn:schemas-upnp-org:device:ScreenDevice:1": omm.MetaHostTypeEnumMultiScreen, "urn:schemas-upnp-org:device:ScreenDevice:2": omm.MetaHostTypeEnumMultiScreen, } ) func Scan(discoverySession session.DiscoverySession) error { devs, err := goupnp.DiscoverDevices(TargetRootDevice) if nil != err { fmt.Println("DiscoverDevices: ", err) return nil } metaIPTypeEnum := omm.ToMetaIPTypeEnum(discoverySession.Zone().MetaIPType) LOOP: for _, dev := range devs { rd := dev.Root.Device if !rd.PresentationURL.Ok { continue LOOP } pURL := rd.PresentationURL.URL ip := oun.ParseIP(pURL.Hostname()) if nil == ip { continue LOOP } switch metaIPTypeEnum { case omm.MetaIPTypeEnumV4: if 4 != ip.Version() { continue LOOP } case omm.MetaIPTypeEnumV6: if 6 != ip.Version() { continue LOOP } default: continue LOOP } meta := map[string]string{ "DeviceType": rd.DeviceType, "FriendlyName": rd.FriendlyName, "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, } h := omd.NewHost( discoverySession.Zone(), discoverySession.Zone().MetaIPType, ip.String(), ) h.Name = rd.ModelName h.DiscoveredDate = omu.NowPtr() mht, ok := deviceTypes[rd.DeviceType] if ok { h.HostType = mht.String() } else { h.HostType = omm.MetaHostTypeEnumHost.String() } discoverySession.AddHost( omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumUPnP), h, meta, ) portNumber, err := strconv.Atoi(pURL.Port()) if nil != err { continue LOOP } p := omd.NewPort( h, omm.ToMetaPortType(omm.MetaPortTypeEnumTCP), portNumber, ) p.DiscoveredDate = omu.NowPtr() p = discoverySession.AddPort( omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumUPnP), p, meta, ) metaCryptoType := omm.ToMetaCryptoType(omm.MetaCryptoTypeEnumNONE) serviceType := omm.MetaServiceTypeEnumUNKNOWN.String() serviceKey := "UNKNOWN" switch strings.ToLower(pURL.Scheme) { case "http": serviceKey = "HTTP" serviceType = omm.MetaServiceTypeEnumWeb.String() case "https": serviceKey = "HTTPS" metaCryptoType = omm.ToMetaCryptoType(omm.MetaCryptoTypeEnumTLS) serviceType = omm.MetaServiceTypeEnumWeb.String() default: } s := omd.NewService( p, metaCryptoType, serviceKey, ) s.Name = pURL.Scheme s.ServiceType = serviceType s.DiscoveredDate = omu.NowPtr() discoverySession.AddService( omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumUPnP), s, meta, ) select { case <-discoverySession.StopChan(): return nil default: } } return nil }