TCPScan is a simple utility for discovering open (or closed) TCP ports on servers. It uses gopacket
(https://github.com/google/gopacket) to craft SYN packets, listening asynchronously for (SYN-)ACK or RST responses without completing the full TCP handshake. TCPScan uses goroutines for asynchronous scans and it searches for the most likely listening ports first, using NMap's "port frequency" ordering. Anecdotal results show that TCPScan is fast!
TCPScan is not a replacement for the awesome NMap tool, but it promises to be a useful library for go applications that need a fast and simple TCP port scanning capability.
TCPScan is also available as a command-line tool.
Prebuilt binaries may be found for your operating system here: https://github.com/adedayo/tcpscan/releases
For macOS X, you could install via brew as follows:
brew tap adedayo/tap
brew install tcpscan
tcpscan 192.168.2.5/30 10.11.12.13/31
For JSON-formatted output simply add the --json
or -j
flag:
tcpscan --json 192.168.2.5/30 10.11.12.13/31
Depending on the fidelity of the network being scanned or the size of CIDR ranges, it may be expedient to adjust the scan timeout accordingly with the --timeout
or -t
flag, which indicates the number of seconds to wait for ACK or RST responses as follows:
tcpscan --json --timeout 5 192.168.2.5/30 10.11.12.13/31
Note that scans generally run faster with shorter timeouts, but you may be sacrificing accuracy on slow networks or for large CIDR ranges.
Usage:
tcpscan [flags]
Examples:
tcpscan 8.8.8.8/32 10.10.10.1/30
Flags:
-h, --help help for tcpscan
-j, --json generate JSON output
-q, --quiet control whether to produce a running commentary of intermediate results or stay quiet till the end
-r, --rate int the rate (in packets per second) that we should send SYN scan packets. This influences overall scan time, but be careful not to overwhelm your network (default 1000)
-s, --service string[="data/config/TCPScanConfig.yml"] run tcpscan as a service (default "data/config/TCPScanConfig.yml")
-t, --timeout int TIMEOUT (in seconds) to adjust how much we are willing to wait for servers to come back with responses. Smaller timeout sacrifices accuracy for speed (default 5)
--version version for tcpscan
In order to start, go get this repository:
go get github.com/adedayo/tcpscan
In your code simply import as usual and enjoy:
package main
import
(
"fmt"
"github.com/adedayo/tcpscan"
)
func main() {
cidr := "8.8.8.8/32"
config := portscan.ScanConfig {
Timeout: 5,
}
result := portscan.ScanCIDR(config, cidr)
for ack := range result {
fmt.Printf("%s:\tPort %s(%s) is %s\n", ack.Host, ack.Port, ack.GetServiceName(), status(ack))
}
}
func status(ack portscan.PortACK) string {
if ack.IsClosed() {
return "Closed"
}
if ack.IsOpen() {
return "Open"
}
return "of Unknown Status"
}
This should produce an output similar to the following:
8.8.8.8: Port 443(https) is Open
8.8.8.8: Port 53(domain) is Open
8.8.8.8: Port 853(domain-s) is Open
You may encounter errors such as
panic: en0: You don't have permission to capture on that device ((cannot open BPF device) /dev/bpf0: Permission denied)
Fix the permission problem permanently by using the "Wireshark" approach of pre-allocating /dev/bpf*, and changing their permissions so that the admin group can read from and write packets to the devices. I have provided the fix-bpf-permissions.sh script to simplify the steps, you can run it as shown below. It will ask for your password for the privileged part of the script, but read the script to satisfy yourself that you trust what it is doing! You care about security, right?
curl -O https://raw.githubusercontent.com/adedayo/tcpscan/master/fix-bpf-permissions.sh
chmod +x fix-bpf-permissions.sh
./fix-bpf-permissions.sh
You should be good to go! You may need to reboot once, but this works across reboots. Note that this is a common problem for tools such as Wireshark, TCPDump etc. that need to read from or write to /dev/bpf*. This solution should fix the problem for all of them - the idea was actually stolen from Wireshark with some modifications :-).
You ideally want to be able to run tcpscan
as an ordinary user, say, my_user
, but since tcpscan
sends raw packets you need to adjust capabilities to allow it to do so. The following may be necessary:
Ensure the following two lines are in /etc/security/capability.conf
cap_net_admin my_user
none *
Also, in /etc/pam.d/login add the following
auth required pam_cap.so
Finally, grant the capability to the tcpscan
file (assuming /path/to is the absolute path to your tcpscan
binary)
setcap cap_net_raw,cap_net_admin=eip /path/to/tcpscan
BSD 3-Clause License