Skip to content

Instantly share code, notes, and snippets.

@CyberRoute
Last active December 31, 2023 14:37
Show Gist options
  • Save CyberRoute/5cd02e1ee10d1c4cef09e5cca1d6f57c to your computer and use it in GitHub Desktop.
Save CyberRoute/5cd02e1ee10d1c4cef09e5cca1d6f57c to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"fmt"
"log"
"net"
//"time"
"github.com/google/gopacket"
"github.com/google/gopacket/examples/util"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/routing"
)
// scanner handles scanning a single IP address.
type scanner struct {
// iface is the interface to send packets on.
iface *net.Interface
// destination, gateway (if applicable), and source IP addresses to use.
dst, gw, src net.IP
handle *pcap.Handle
// opts and buf allow us to easily serialize packets in the send()
// method.
opts gopacket.SerializeOptions
buf gopacket.SerializeBuffer
}
// newScanner creates a new scanner for a given destination IP address, using
// router to determine how to route packets to that IP.
func newScanner(ip net.IP, router routing.Router) {
s := &scanner{
dst: ip,
opts: gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
},
buf: gopacket.NewSerializeBuffer(),
}
// Figure out the route to the IP.
iface, gw, src, _ := router.Route(ip)
log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src)
// Open the handle for reading/writing.
// Note we could very easily add some BPF filtering here to greatly
// decrease the number of packets we have to look at when getting back
// scan results.
handle, _ := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
defer handle.Close()
arpDst := ip
if gw != nil {
arpDst = gw
}
// Prepare the layers to send for an ARP request.
eth := layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
EthernetType: layers.EthernetTypeARP,
}
arp := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv4,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: layers.ARPRequest,
SourceHwAddress: []byte(iface.HardwareAddr),
SourceProtAddress: []byte(src),
DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
DstProtAddress: []byte(arpDst),
}
// Send a single ARP request packet (we never retry a send, since this
// SerializeLayers clears the given write buffer, then writes all layers
// into it so they correctly wrap each other. Note that by clearing the buffer,
// it invalidates all slices previously returned by w.Bytes()
gopacket.SerializeLayers(s.buf, s.opts, &eth, &arp)
handle.WritePacketData(s.buf.Bytes()) // WritePacketData calls pcap_sendpacket, injecting the given data into the pcap handle
var dstmacaddress net.HardwareAddr
for {
data, _, err := handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
break
}
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &arp)
decoded := []gopacket.LayerType{}
if err := parser.DecodeLayers(data, &decoded); err != nil {
}
for _, layerType := range decoded {
switch layerType {
case layers.LayerTypeEthernet:
if net.IP(arp.SourceProtAddress).Equal(net.IP(arpDst)) {
dstmacaddress = net.HardwareAddr(arp.SourceHwAddress)
}
}
}
fmt.Println("dstmacaddress filled:", dstmacaddress)
if dstmacaddress != nil {
fmt.Println("Exiting loop.")
break
}
}
eth = layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: dstmacaddress,
EthernetType: layers.EthernetTypeIPv4,
}
ip4 := layers.IPv4{
SrcIP: src,
DstIP: ip,
Version: 4,
TTL: 64,
Protocol: layers.IPProtocolTCP,
}
tcp := layers.TCP{
SrcPort: 54321,
DstPort: 0, // will be incremented during the scan
SYN: true,
}
tcp.SetNetworkLayerForChecksum(&ip4)
//start := time.Now()
//ipFlow := gopacket.NewFlow(layers.EndpointIPv4, ip, src)
for {
// Send one packet per loop iteration until we've sent packets
// to all of ports [1, 65535].
if tcp.DstPort < 65535 {
tcp.DstPort++
gopacket.SerializeLayers(s.buf, s.opts, &eth, &ip4, &tcp)
handle.WritePacketData(s.buf.Bytes())
}
// Time out 5 seconds after the last packet we sent.
// if time.Since(start) > time.Second*5 {
// log.Printf("timed out for %v, assuming we've seen all we can", s.dst)
// }
eth := &layers.Ethernet{}
ip4 := &layers.IPv4{}
tcp := &layers.TCP{}
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, eth, ip4, tcp)
decodedLayers := make([]gopacket.LayerType, 0, 4)
// Read in the next packet.
data, _, err := handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
log.Printf("error reading packet: %v", err)
continue
}
// Parse the packet. Using DecodingLayerParser to be really fast
if err := parser.DecodeLayers(data, &decodedLayers); err != nil {
fmt.Println("Error", err)
}
for _, typ := range decodedLayers {
switch typ {
// case layers.LayerTypeEthernet:
// fmt.Println(" Eth ", eth1.SrcMAC, eth1.DstMAC)
// continue
// case layers.LayerTypeIPv4:
// fmt.Println(" IP4 ", ip41.SrcIP, ip41.DstIP)
// if ip41.NetworkFlow() != ipFlow {
// continue
// }
// continue
case layers.LayerTypeTCP:
//fmt.Println(" TCP ", tcp1.SrcPort, tcp1.DstPort)
if tcp.DstPort != 54321 {
continue
} else if tcp.SYN && tcp.ACK {
log.Printf(" port %v open", tcp.SrcPort)
continue
} else if tcp.RST {
log.Printf(" port %v closed", tcp.SrcPort)
continue
}
}
}
}
}
func main() {
defer util.Run()()
router, err := routing.New()
if err != nil {
log.Fatal("routing error:", err)
}
for _, arg := range flag.Args() {
var ip net.IP
if ip = net.ParseIP(arg); ip == nil {
log.Printf("non-ip target: %q", arg)
continue
} else if ip = ip.To4(); ip == nil {
log.Printf("non-ipv4 target: %q", arg)
continue
}
newScanner(ip, router)
if err != nil {
log.Printf("unable to create scanner for %v: %v", ip, err)
continue
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment