diff --git a/cmd/scan.go b/cmd/scan.go new file mode 100644 index 0000000..6ac5b59 --- /dev/null +++ b/cmd/scan.go @@ -0,0 +1,84 @@ +// Copyright © 2024 Martin Holst Swende +// +// 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 cmd + +import ( + "fmt" + "net" + "sync" + "time" + + "github.com/seancfoley/ipaddress-go/ipaddr" + "github.com/spf13/cobra" +) + +// scanCmd triggers a scan +var scanCmd = &cobra.Command{ + Use: "scan", + Short: "Scan for chromecast devices", + Run: func(cmd *cobra.Command, args []string) { + var ( + cidrAddr, _ = cmd.Flags().GetString("cidr") + port, _ = cmd.Flags().GetInt("port") + wg sync.WaitGroup + uriCh = make(chan string) + logged = time.Unix(0, 0) + start = time.Now() + count int + ipRange, err = ipaddr.NewIPAddressString(cidrAddr).ToSequentialRange() + ) + if err != nil { + exit("could not parse cidr address expression: %v", err) + } + // Use one goroutine to send URIs over a channel + go func() { + it := ipRange.Iterator() + for it.HasNext() { + uri := fmt.Sprintf("%s:%d", it.Next(), port) + if time.Since(logged) > 8*time.Second { + outputInfo("Scanning... scanned %d, current %v\n", count, uri) + logged = time.Now() + } + uriCh <- uri + count++ + } + close(uriCh) + }() + // Use a bunch of goroutines to do connect-attempts. + for i := 0; i < 64; i++ { + wg.Add(1) + go func() { + defer wg.Done() + dialer := &net.Dialer{ + Timeout: 400 * time.Millisecond, + } + for uri := range uriCh { + if conn, err := dialer.Dial("tcp", uri); err == nil { + conn.Close() + outputInfo("Found (potential) chromecast at %v\n", uri) + } + } + }() + } + wg.Wait() + outputInfo("Scanned %d uris in %v\n", count, time.Since(start)) + }, +} + +func init() { + scanCmd.Flags().String("cidr", "192.168.50.0/24", "cidr expression of subnet to scan") + scanCmd.Flags().Int("port", 8009, "port to scan for") + rootCmd.AddCommand(scanCmd) +} diff --git a/go.mod b/go.mod index 7316b4c..a72f961 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 ) +require github.com/seancfoley/ipaddress-go v1.5.5 require gopkg.in/ini.v1 v1.67.0 require ( @@ -42,6 +43,7 @@ require ( github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/seancfoley/bintree v1.2.3 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect go.opencensus.io v0.24.0 // indirect diff --git a/go.sum b/go.sum index ebb75e6..c54fcec 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,10 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/seancfoley/bintree v1.2.3 h1:6SPPax/9Dilcs3mDTj3CarRCWPZJV30KyP3cjcEwF70= +github.com/seancfoley/bintree v1.2.3/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU= +github.com/seancfoley/ipaddress-go v1.5.5 h1:Q2isCacDQ3A46hxSbM9Q2+Gs4IopCVz1oH88L5eEgP4= +github.com/seancfoley/ipaddress-go v1.5.5/go.mod h1:C+VHKCmxTfYODkkItOj9lMemZLMigwo28E+ARlPqpk0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=