diff --git a/modules/dhcp6_spoof/dhcp6_spoof.go b/modules/dhcp6_spoof/dhcp6_spoof.go index 56d88388..9c4fefd2 100644 --- a/modules/dhcp6_spoof/dhcp6_spoof.go +++ b/modules/dhcp6_spoof/dhcp6_spoof.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/session" @@ -83,7 +84,7 @@ func (mod *DHCP6Spoofer) Configure() error { return session.ErrAlreadyStarted(mod.Name()) } - if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { + if mod.Handle, err = network.Capture(mod.Session.Interface.Name()); err != nil { return err } diff --git a/modules/dns_spoof/dns_spoof.go b/modules/dns_spoof/dns_spoof.go index ab9a350a..03a42f26 100644 --- a/modules/dns_spoof/dns_spoof.go +++ b/modules/dns_spoof/dns_spoof.go @@ -8,6 +8,7 @@ import ( "sync" "github.com/bettercap/bettercap/log" + "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/session" @@ -100,7 +101,7 @@ func (mod *DNSSpoofer) Configure() error { if mod.Running() { return session.ErrAlreadyStarted(mod.Name()) - } else if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { + } else if mod.Handle, err = network.Capture(mod.Session.Interface.Name()); err != nil { return err } else if err = mod.Handle.SetBPFFilter("udp"); err != nil { return err diff --git a/modules/http_proxy/http_proxy_base_sslstriper.go b/modules/http_proxy/http_proxy_base_sslstriper.go index 2a99ac01..3c029eba 100644 --- a/modules/http_proxy/http_proxy_base_sslstriper.go +++ b/modules/http_proxy/http_proxy_base_sslstriper.go @@ -5,12 +5,13 @@ import ( "net/http" "net/url" "regexp" - "strings" "strconv" + "strings" "github.com/bettercap/bettercap/log" - "github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/modules/dns_spoof" + "github.com/bettercap/bettercap/network" + "github.com/bettercap/bettercap/session" "github.com/elazarl/goproxy" "github.com/google/gopacket" @@ -23,9 +24,9 @@ import ( ) var ( - httpsLinksParser = regexp.MustCompile(`https://[^"'/]+`) + httpsLinksParser = regexp.MustCompile(`https://[^"'/]+`) domainCookieParser = regexp.MustCompile(`; ?(?i)domain=.*(;|$)`) - flagsCookieParser = regexp.MustCompile(`; ?(?i)(secure|httponly)`) + flagsCookieParser = regexp.MustCompile(`; ?(?i)(secure|httponly)`) ) type SSLStripper struct { @@ -83,7 +84,7 @@ func (s *SSLStripper) Enable(enabled bool) { if enabled && s.handle == nil { var err error - if s.handle, err = pcap.OpenLive(s.session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { + if s.handle, err = network.Capture(s.session.Interface.Name()); err != nil { panic(err) } @@ -168,7 +169,7 @@ func (s *SSLStripper) fixCookies(res *http.Response) { origDomain := origParts[len(origParts)-2] + "." + origParts[len(origParts)-1] strippedDomain := strippedParts[len(strippedParts)-2] + "." + strippedParts[len(strippedParts)-1] - log.Info("[%s] Fixing cookies on %s", tui.Green("sslstrip"),tui.Bold(strippedHost.Hostname)) + log.Info("[%s] Fixing cookies on %s", tui.Green("sslstrip"), tui.Bold(strippedHost.Hostname)) cookies := make([]string, len(res.Header["Set-Cookie"])) // replace domain and strip "secure" flag for each cookie for i, cookie := range res.Header["Set-Cookie"] { diff --git a/modules/net_sniff/net_sniff_context.go b/modules/net_sniff/net_sniff_context.go index 3ebcd9f1..bb21afb3 100644 --- a/modules/net_sniff/net_sniff_context.go +++ b/modules/net_sniff/net_sniff_context.go @@ -6,6 +6,7 @@ import ( "time" "github.com/bettercap/bettercap/log" + "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/session" "github.com/google/gopacket/pcap" @@ -42,7 +43,7 @@ func (mod *Sniffer) GetContext() (error, *SnifferContext) { * could hang waiting for a timeout to expire ... */ readTimeout := 500 * time.Millisecond - if ctx.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, readTimeout); err != nil { + if ctx.Handle, err = network.CaptureWithTimeout(mod.Session.Interface.Name(), readTimeout); err != nil { return err, ctx } } else { diff --git a/modules/syn_scan/syn_scan.go b/modules/syn_scan/syn_scan.go index b03b79a8..0ce89954 100644 --- a/modules/syn_scan/syn_scan.go +++ b/modules/syn_scan/syn_scan.go @@ -7,6 +7,7 @@ import ( "sync/atomic" "time" + "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/session" @@ -115,7 +116,7 @@ func (mod *SynScanner) Configure() (err error) { return session.ErrAlreadyStarted(mod.Name()) } if mod.handle == nil { - if mod.handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { + if mod.handle, err = network.Capture(mod.Session.Interface.Name()); err != nil { return err } else if err = mod.handle.SetBPFFilter(fmt.Sprintf("tcp dst port %d", synSourcePort)); err != nil { return err diff --git a/modules/wifi/wifi.go b/modules/wifi/wifi.go index a566efe5..411739cd 100644 --- a/modules/wifi/wifi.go +++ b/modules/wifi/wifi.go @@ -91,7 +91,7 @@ func NewWiFiModule(s *session.Session) *WiFiModule { assocOpen: false, assocAcquired: false, csaSilent: false, - fakeAuthSilent: false, + fakeAuthSilent: false, showManuf: false, shakesAggregate: true, writes: &sync.WaitGroup{}, @@ -226,11 +226,11 @@ func NewWiFiModule(s *session.Session) *WiFiModule { if err != nil { return err } - channel,_:=strconv.Atoi( args[1]) - if channel>180 || channel<1{ - return fmt.Errorf("%d is not a valid channel number",channel) + channel, _ := strconv.Atoi(args[1]) + if channel > 180 || channel < 1 { + return fmt.Errorf("%d is not a valid channel number", channel) } - return mod.startCSA(bssid,int8(channel)) + return mod.startCSA(bssid, int8(channel)) }) channelSwitchAnnounce.Complete("wifi.channel_switch_announce", s.WiFiCompleterFull) @@ -244,11 +244,11 @@ func NewWiFiModule(s *session.Session) *WiFiModule { if err != nil { return err } - client,err:=net.ParseMAC(args[1]) - if err!=nil{ + client, err := net.ParseMAC(args[1]) + if err != nil { return err } - return mod.startFakeAuth(bssid,client) + return mod.startFakeAuth(bssid, client) }) fakeAuth.Complete("wifi.fake_auth", s.WiFiCompleterFull) @@ -556,53 +556,33 @@ func (mod *WiFiModule) Configure() error { } } - setRFMonMaybeFatal := false + /* + * We don't want to pcap.BlockForever otherwise pcap_close(handle) + * could hang waiting for a timeout to expire ... + */ + opts := network.CAPTURE_DEFAULTS + opts.Timeout = 500 * time.Millisecond + opts.Monitor = true + for retry := 0; ; retry++ { - ihandle, err := pcap.NewInactiveHandle(ifName) - if err != nil { - return fmt.Errorf("error while opening interface %s: %s", ifName, err) - } - defer ihandle.CleanUp() - - /* - * Calling SetRFMon is fatal when the interface is already in monitor mode. - * gopacket has no GetRFMon analogue to SetRFMon with which we could check this, however ... - */ - if !setRFMonMaybeFatal { - if err = ihandle.SetRFMon(true); err != nil { - return fmt.Errorf("error while setting interface %s in monitor mode: %s", tui.Bold(ifName), err) + if mod.handle, err = network.CaptureWithOptions(ifName, opts); err == nil { + // we're done + break + } else if retry == 0 /* && err.Error() == ErrIfaceNotUp */ { + // try to bring interface up and try again + mod.Info("interface %s is down, bringing it up ...", ifName) + if err := network.ActivateInterface(ifName); err != nil { + return err } + continue + } else if !opts.Monitor { + // second fatal error, just bail + return fmt.Errorf("error while activating handle: %s", err) } else { - mod.Debug("SetRFMon on interface %s might be fatal, skipping this time", tui.Bold(ifName)) + // first fatal error, try again without setting the interface in monitor mode + mod.Warning("error while activating handle: %s, %s", err, tui.Bold("interface might already be monitoring. retrying!")) + opts.Monitor = false } - if err = ihandle.SetSnapLen(65536); err != nil { - return fmt.Errorf("error while settng snapshot length: %s", err) - } - /* - * We don't want to pcap.BlockForever otherwise pcap_close(handle) - * could hang waiting for a timeout to expire ... - */ - readTimeout := 500 * time.Millisecond - if err = ihandle.SetTimeout(readTimeout); err != nil { - return fmt.Errorf("error while setting timeout: %s", err) - } else if mod.handle, err = ihandle.Activate(); err != nil { - if retry == 0 && err.Error() == ErrIfaceNotUp { - mod.Debug("interface %s is down, bringing it up ...", ifName) - if err := network.ActivateInterface(ifName); err != nil { - return err - } - continue - } - if setRFMonMaybeFatal { - return fmt.Errorf("error while activating handle: %s", err) - } else { - mod.Warning("error while activating handle: %s, %s", err, tui.Bold("interface might already be monitoring. retrying!")) - setRFMonMaybeFatal = true - continue - } - } - - break } } diff --git a/network/pcap.go b/network/pcap.go new file mode 100644 index 00000000..62ec5657 --- /dev/null +++ b/network/pcap.go @@ -0,0 +1,71 @@ +package network + +import ( + "fmt" + "time" + + "github.com/evilsocket/islazy/tui" + "github.com/google/gopacket/pcap" +) + +const ( + PCAP_DEFAULT_SETRF = false + PCAP_DEFAULT_SNAPLEN = 65536 + PCAP_DEFAULT_BUFSIZE = 2_097_152 + PCAP_DEFAULT_PROMISC = true + PCAP_DEFAULT_TIMEOUT = pcap.BlockForever +) + +var CAPTURE_DEFAULTS = CaptureOptions{ + Monitor: PCAP_DEFAULT_SETRF, + Snaplen: PCAP_DEFAULT_SNAPLEN, + Bufsize: PCAP_DEFAULT_BUFSIZE, + Promisc: PCAP_DEFAULT_PROMISC, + Timeout: PCAP_DEFAULT_TIMEOUT, +} + +type CaptureOptions struct { + Monitor bool + Snaplen int + Bufsize int + Promisc bool + Timeout time.Duration +} + +func CaptureWithOptions(ifName string, options CaptureOptions) (*pcap.Handle, error) { + Debug("creating capture for '%s' with options: %+v", ifName, options) + + ihandle, err := pcap.NewInactiveHandle(ifName) + if err != nil { + return nil, fmt.Errorf("error while opening interface %s: %s", ifName, err) + } + defer ihandle.CleanUp() + + if options.Monitor { + if err = ihandle.SetRFMon(true); err != nil { + return nil, fmt.Errorf("error while setting interface %s in monitor mode: %s", tui.Bold(ifName), err) + } + } + + if err = ihandle.SetSnapLen(options.Snaplen); err != nil { + return nil, fmt.Errorf("error while settng snapshot length: %s", err) + } else if err = ihandle.SetBufferSize(options.Bufsize); err != nil { + return nil, fmt.Errorf("error while settng buffer size: %s", err) + } else if err = ihandle.SetPromisc(options.Promisc); err != nil { + return nil, fmt.Errorf("error while settng promiscuous mode to %v: %s", options.Promisc, err) + } else if err = ihandle.SetTimeout(options.Timeout); err != nil { + return nil, fmt.Errorf("error while settng snapshot length: %s", err) + } + + return ihandle.Activate() +} + +func Capture(ifName string) (*pcap.Handle, error) { + return CaptureWithOptions(ifName, CAPTURE_DEFAULTS) +} + +func CaptureWithTimeout(ifName string, timeout time.Duration) (*pcap.Handle, error) { + var opts = CAPTURE_DEFAULTS + opts.Timeout = timeout + return CaptureWithOptions(ifName, opts) +} diff --git a/packets/queue.go b/packets/queue.go index 7bca2840..b8242ea9 100644 --- a/packets/queue.go +++ b/packets/queue.go @@ -69,7 +69,7 @@ func NewQueue(iface *network.Endpoint) (q *Queue, err error) { } if q.active { - if q.handle, err = pcap.OpenLive(iface.Name(), 1024, true, pcap.BlockForever); err != nil { + if q.handle, err = network.Capture(iface.Name()); err != nil { return }