Skip to content

Commit

Permalink
Merge pull request #34 from projectdiscovery/feature-socket-only
Browse files Browse the repository at this point in the history
Feature socket only
  • Loading branch information
ehsandeep authored Jun 6, 2020
2 parents fa37979 + 8a6ffb0 commit b4ebd6b
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 89 deletions.
5 changes: 0 additions & 5 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ jobs:
- name: Check out code
uses: actions/checkout@v2

- name: Install libpcap
run: |
sudo apt-get update
sudo apt install libpcap-dev
- name: Test
run: go test .
working-directory: cmd/naabu/
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Release
on:
create:
tags:
- v*

jobs:
release:
name: Release on GitHub
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v1

- name: Validates GO releaser config
uses: docker://goreleaser/goreleaser:latest
with:
args: check

- name: Create release on GitHub
uses: docker://goreleaser/goreleaser:latest
with:
args: release
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
21 changes: 21 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
builds:
- binary: nuclei
main: cmd/naabu/main.go
goos:
- linux
- windows
- darwin
goarch:
- amd64
- 386
- arm
- arm64

archives:
- id: tgz
format: tar.gz
replacements:
darwin: macOS
format_overrides:
- goos: windows
format: zip
6 changes: 0 additions & 6 deletions cmd/naabu/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main

import (
"os"

"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/naabu/pkg/runner"
)
Expand All @@ -11,10 +9,6 @@ func main() {
// Parse the command line flags and read config files
options := runner.ParseOptions()

if os.Geteuid() > 0 {
gologger.Fatalf("Exiting, You must be a privileged user to run this scan\n")
}

runner, err := runner.NewRunner(options)
if err != nil {
gologger.Fatalf("Could not create runner: %s\n", err)
Expand Down
10 changes: 9 additions & 1 deletion pkg/runner/enumerate.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,15 @@ func (r *Runner) EnumerateSingleHost(host string, ports map[int]struct{}, output
gologger.Warningf("Could not start scan on host %s (%s): %s\n", host, hostIP, err)
return
}
results, err := scanner.Scan(ports)

var results map[int]struct{}

if os.Geteuid() > 0 {
results, err = scanner.ScanConnect(ports)
} else {
results, err = scanner.ScanSyn(ports)
}

if err != nil {
gologger.Warningf("Could not scan on host %s (%s): %s\n", host, hostIP, err)
return
Expand Down
152 changes: 75 additions & 77 deletions pkg/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package scan

import (
"fmt"
"io"
"math"
"math/rand"
"net"
Expand All @@ -12,9 +11,9 @@ import (

"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/phayes/freeport"
"github.com/projectdiscovery/gologger"
"github.com/remeh/sizedwaitgroup"
)

// Scanner is a scanner that scans for ports using SYN packets.
Expand Down Expand Up @@ -69,48 +68,16 @@ func (s *Scanner) send(conn net.PacketConn, l ...gopacket.SerializableLayer) (in
return conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: s.host})
}

// Scan scans a single host and returns the results
func (s *Scanner) Scan(wordlist map[int]struct{}) (map[int]struct{}, error) {
inactive, err := pcap.NewInactiveHandle(s.networkInterface.Name)
if err != nil {
return nil, err
}
inactive.SetSnapLen(65536)

readTimeout := time.Duration(1500) * time.Millisecond
if err = inactive.SetTimeout(readTimeout); err != nil {
inactive.CleanUp()
return nil, err
}
inactive.SetImmediateMode(true)

handle, err := inactive.Activate()
// ScanSyn scans a single host and returns the results
func (s *Scanner) ScanSyn(wordlist map[int]struct{}) (map[int]struct{}, error) {
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
inactive.CleanUp()
return nil, err
}
defer conn.Close()

rawPort, err := freeport.GetFreePort()
if err != nil {
handle.Close()
inactive.CleanUp()
return nil, err
}

// Strict BPF filter
// + Packets coming from target ip
// + Destination port equals to sender socket source port
err = handle.SetBPFFilter(fmt.Sprintf("tcp and port %d and ip host %s", rawPort, s.host))
if err != nil {
handle.Close()
inactive.CleanUp()
return nil, err
}

conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
handle.Close()
inactive.CleanUp()
return nil, err
}

Expand Down Expand Up @@ -155,53 +122,35 @@ func (s *Scanner) Scan(wordlist map[int]struct{}) (map[int]struct{}, error) {

tasksWg := &sync.WaitGroup{}
tasksWg.Add(1)
ipFlow := gopacket.NewFlow(layers.EndpointIPv4, s.host, s.srcIP)

go func() {
var (
eth layers.Ethernet
ip4 layers.IPv4
tcp layers.TCP
parser *gopacket.DecodingLayerParser
)

if s.networkInterface.HardwareAddr != nil {
// Interfaces with MAC (Physical + Virtualized)
parser = gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip4, &tcp)
} else {
// Interfaces without MAC (TUN/TAP)
parser = gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &ip4, &tcp)
}

decoded := []gopacket.LayerType{}
defer tasksWg.Done()
data := make([]byte, 4096)
for {
data, _, err := handle.ReadPacketData()
if err == io.EOF {
n, addr, err := conn.ReadFrom(data)
if err != nil {
break
} else if err != nil {
continue
}

if err := parser.DecodeLayers(data, &decoded); err != nil {
// not matching ip
if addr.String() != s.host.String() {
continue
}
for _, layerType := range decoded {
switch layerType {
case layers.LayerTypeIPv4:
if ip4.NetworkFlow() != ipFlow {
continue
}
case layers.LayerTypeTCP:
// We consider only incoming packets
if tcp.DstPort != layers.TCPPort(rawPort) {
continue
} else if tcp.SYN && tcp.ACK {
openChan <- int(tcp.SrcPort)
}

packet := gopacket.NewPacket(data[:n], layers.LayerTypeTCP, gopacket.Default)
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, ok := tcpLayer.(*layers.TCP)
if !ok {
continue
}
// We consider only incoming packets
if tcp.DstPort != layers.TCPPort(rawPort) {
continue
} else if tcp.SYN && tcp.ACK {
openChan <- int(tcp.SrcPort)
}
}
}
tasksWg.Done()
}()

limiter := time.Tick(time.Second / time.Duration(s.rate))
Expand Down Expand Up @@ -233,20 +182,69 @@ func (s *Scanner) Scan(wordlist map[int]struct{}) (map[int]struct{}, error) {
// Just like masscan, wait for 10 seconds for further packets
if s.timeout > 0 {
timer := time.AfterFunc(10*time.Second, func() {
handle.Close()
conn.Close()
})
defer timer.Stop()
} else {
handle.Close()
conn.Close()
}

tasksWg.Wait()
close(openChan)
resultsWg.Wait()

inactive.CleanUp()
return results, nil
}

// ScanConnect a single host and returns the results
func (s *Scanner) ScanConnect(wordlist map[int]struct{}) (map[int]struct{}, error) {
openChan := make(chan int)
results := make(map[int]struct{})
resultsWg := &sync.WaitGroup{}
resultsWg.Add(1)

go func() {
for open := range openChan {
gologger.Debugf("Found active port %d on %s\n", open, s.host.String())

results[open] = struct{}{}
}
resultsWg.Done()
}()

tasksWg := &sync.WaitGroup{}
tasksWg.Add(1)

ports := make(chan int)
go func() {
defer tasksWg.Done()

swgscan := sizedwaitgroup.New(s.rate)
for port := range ports {
swgscan.Add()
go func(port int) {
defer swgscan.Done()

conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", s.host, port), s.timeout)
if err != nil {
return
}
defer conn.Close()

openChan <- port
}(port)
}
swgscan.Wait()
}()

for port := range wordlist {
ports <- port
}
close(ports)

tasksWg.Wait()
close(openChan)
resultsWg.Wait()

return results, nil
}
Expand Down

0 comments on commit b4ebd6b

Please sign in to comment.