11package command
22
33import (
4+ "bufio"
45 "context"
56 "errors"
67 "io"
@@ -63,13 +64,14 @@ var rootCmd = &cobra.Command{
6364}
6465
6566var (
66- cliJSONFlag bool
67- cliInterfaceFlag string
68- cliSrcIPFlag string
69- cliSrcMACFlag string
70- cliPortsFlag string
71- cliRateLimitFlag string
72- cliExitDelayFlag string
67+ cliJSONFlag bool
68+ cliInterfaceFlag string
69+ cliSrcIPFlag string
70+ cliSrcMACFlag string
71+ cliPortsFlag string
72+ cliRateLimitFlag string
73+ cliExitDelayFlag string
74+ cliARPCacheFileFlag string
7375
7476 cliInterface * net.Interface
7577 cliSrcIP net.IP
8587 errSrcMAC = errors .New ("invalid source MAC" )
8688 errSrcInterface = errors .New ("invalid source interface" )
8789 errRateLimit = errors .New ("invalid ratelimit" )
90+ errStdin = errors .New ("stdin is from a terminal" )
8891)
8992
9093func init () {
@@ -128,10 +131,8 @@ func parseScanConfig(scanName, subnet string) (c *scanConfig, err error) {
128131 return
129132 }
130133
131- // TODO file argument
132- // TODO handle pipes
133- cache := arp .NewCache ()
134- if err = arp .FillCache (cache , os .Stdin ); err != nil {
134+ var cache * arp.Cache
135+ if cache , err = parseARPCache (); err != nil {
135136 return
136137 }
137138
@@ -148,6 +149,32 @@ func parseScanConfig(scanName, subnet string) (c *scanConfig, err error) {
148149 return
149150}
150151
152+ func parseARPCache () (cache * arp.Cache , err error ) {
153+ var r io.Reader
154+ if len (cliARPCacheFileFlag ) > 0 {
155+ var f * os.File
156+ if f , err = os .Open (cliARPCacheFileFlag ); err != nil {
157+ return
158+ }
159+ defer f .Close ()
160+ r = bufio .NewReader (f )
161+ } else {
162+ var info os.FileInfo
163+ if info , err = os .Stdin .Stat (); err != nil {
164+ return
165+ }
166+ // only data being piped to stdin is valid
167+ if (info .Mode () & os .ModeCharDevice ) != 0 {
168+ // stdin from terminal is not valid
169+ return nil , errStdin
170+ }
171+ r = os .Stdin
172+ }
173+ cache = arp .NewCache ()
174+ err = arp .FillCache (cache , r )
175+ return
176+ }
177+
151178func parseScanRange (subnet string ) (* scan.Range , error ) {
152179 dstSubnet , err := ip .ParseIPNet (subnet )
153180 if err != nil {
0 commit comments