Skip to content

Instantly share code, notes, and snippets.

@adrianlzt
Created July 6, 2022 06:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adrianlzt/69b25104529684f9eaf7c33462deedac to your computer and use it in GitHub Desktop.
Save adrianlzt/69b25104529684f9eaf7c33462deedac to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"net"
"os"
"time"
)
var expectedPort = 80
// Max number of packages allowed outside of the expected port.
// Kill the app if this number is reached.
var scannerThreshold = 3
func main() {
go func() {
serverIp := net.ParseIP("0.0.0.0").To4()
conn, err := net.ListenIP("ip4:tcp", &net.IPAddr{IP: serverIp})
if err != nil {
fmt.Printf("ListenIP: %v", err.Error())
}
// Counter of number of packages received
count := 0
b := make([]byte, 1024)
var tcp TCPHeader
for {
numRead, remoteAddr, err := conn.ReadFromIP(b)
if err != nil {
fmt.Printf("read from ip:%s", err.Error())
continue
}
NewTCPHeader(b[:numRead], &tcp)
if tcp.HasFlag(RST) || tcp.HasFlag(ACK) {
continue
}
port := int(tcp.Destination)
ip := remoteAddr.IP
ipString := ip.String()
fmt.Printf("tcp packet from %s:%d\n", ipString, port)
if port != expectedPort {
count++
}
if count >= scannerThreshold {
fmt.Printf("Scanner detected from %s:%d\n", ipString, port)
os.Exit(1)
}
}
}()
for {
fmt.Println(".")
time.Sleep(3 * time.Second)
}
}
/*
this file origins from: https://github.com/grahamking/latency/blob/master/tcp.go
and I modify a little as need;
*/
/*
Copyright 2013-2014 Graham King
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
For full license details see <http://www.gnu.org/licenses/>.
*/
package main
import (
"bytes"
"encoding/binary"
)
const (
FIN = 1 // 00 0001
SYN = 2 // 00 0010
RST = 4 // 00 0100
PSH = 8 // 00 1000
ACK = 16 // 01 0000
URG = 32 // 10 0000
)
type TCPHeader struct {
Source uint16
Destination uint16
SeqNum uint32
AckNum uint32
DataOffset uint8 // 4 bits
Reserved uint8 // 3 bits
ECN uint8 // 3 bits
Ctrl uint8 // 6 bits
Window uint16
Checksum uint16 // Kernel will set this if it's 0
Urgent uint16
Options []TCPOption
}
type TCPOption struct {
Kind uint8
Length uint8
Data []byte
}
// Parse packet into TCPHeader structure
func NewTCPHeader(data []byte, tcp *TCPHeader) *TCPHeader {
r := bytes.NewReader(data)
binary.Read(r, binary.BigEndian, &tcp.Source)
binary.Read(r, binary.BigEndian, &tcp.Destination)
binary.Read(r, binary.BigEndian, &tcp.SeqNum)
binary.Read(r, binary.BigEndian, &tcp.AckNum)
var mix uint16
binary.Read(r, binary.BigEndian, &mix)
tcp.DataOffset = byte(mix >> 12) // top 4 bits
tcp.Reserved = byte(mix >> 9 & 7) // 3 bits
tcp.ECN = byte(mix >> 6 & 7) // 3 bits
tcp.Ctrl = byte(mix & 0x3f) // bottom 6 bits
binary.Read(r, binary.BigEndian, &tcp.Window)
binary.Read(r, binary.BigEndian, &tcp.Checksum)
binary.Read(r, binary.BigEndian, &tcp.Urgent)
return tcp
}
func (tcp *TCPHeader) HasFlag(flagBit byte) bool {
return tcp.Ctrl&flagBit != 0
}
func (tcp *TCPHeader) Marshal() []byte {
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, tcp.Source)
binary.Write(buf, binary.BigEndian, tcp.Destination)
binary.Write(buf, binary.BigEndian, tcp.SeqNum)
binary.Write(buf, binary.BigEndian, tcp.AckNum)
var mix uint16
mix = uint16(tcp.DataOffset)<<12 | // top 4 bits
uint16(tcp.Reserved)<<9 | // 3 bits
uint16(tcp.ECN)<<6 | // 3 bits
uint16(tcp.Ctrl) // bottom 6 bits
binary.Write(buf, binary.BigEndian, mix)
binary.Write(buf, binary.BigEndian, tcp.Window)
binary.Write(buf, binary.BigEndian, tcp.Checksum)
binary.Write(buf, binary.BigEndian, tcp.Urgent)
for _, option := range tcp.Options {
binary.Write(buf, binary.BigEndian, option.Kind)
if option.Length > 1 {
binary.Write(buf, binary.BigEndian, option.Length)
binary.Write(buf, binary.BigEndian, option.Data)
}
}
out := buf.Bytes()
// Pad to min tcp header size, which is 20 bytes (5 32-bit words)
pad := 20 - len(out)
for i := 0; i < pad; i++ {
out = append(out, 0)
}
return out
}
// TCP Checksum
func csum(data []byte, srcip, dstip [4]byte) uint16 {
pseudoHeader := []byte{
srcip[0], srcip[1], srcip[2], srcip[3],
dstip[0], dstip[1], dstip[2], dstip[3],
0, // zero
6, // protocol number (6 == TCP)
0, byte(len(data)), // TCP length (16 bits), not inc pseudo header
}
sumThis := make([]byte, 0, len(pseudoHeader)+len(data))
sumThis = append(sumThis, pseudoHeader...)
sumThis = append(sumThis, data...)
//fmt.Printf("% x\n", sumThis)
lenSumThis := len(sumThis)
var nextWord uint16
var sum uint32
for i := 0; i+1 < lenSumThis; i += 2 {
nextWord = uint16(sumThis[i])<<8 | uint16(sumThis[i+1])
sum += uint32(nextWord)
}
if lenSumThis%2 != 0 {
//fmt.Println("Odd byte")
sum += uint32(sumThis[len(sumThis)-1])
}
// Add back any carry, and any carry from adding the carry
sum = (sum >> 16) + (sum & 0xffff)
sum = sum + (sum >> 16)
// Bitwise complement
return uint16(^sum)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment