Last active
December 31, 2023 14:37
-
-
Save CyberRoute/5cd02e1ee10d1c4cef09e5cca1d6f57c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, ð, &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, ð, &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, ð, &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