Reorganize directory structures

Signed-off-by: Sean Du <do4suki@gmail.com>
This commit is contained in:
2025-08-05 20:06:35 +08:00
parent d666470272
commit adf2a72630
2087 changed files with 637 additions and 603 deletions
+63
View File
@@ -0,0 +1,63 @@
package db
import (
"fmt"
"honoka-chan/pkg/utils"
"os"
_ "modernc.org/sqlite"
"xorm.io/xorm"
)
var (
DB *Instance
ExampleDb = "assets/data.example.db"
MainDb = "assets/main.db"
UserDb = "assets/data.db"
MainEng *xorm.Engine
UserEng *xorm.Engine
)
func init() {
DB = GetInstance()
_, err := os.Stat(UserDb)
if err != nil {
utils.WriteAllText(UserDb, utils.ReadAllText(ExampleDb))
}
eng, err := xorm.NewEngine("sqlite", MainDb)
if err != nil {
panic(err)
}
err = eng.Ping()
if err != nil {
panic(err)
}
eng.SetMaxOpenConns(10)
eng.SetMaxIdleConns(5)
MainEng = eng
eng, err = xorm.NewEngine("sqlite", UserDb)
if err != nil {
panic(err)
}
err = eng.Ping()
if err != nil {
panic(err)
}
eng.SetMaxOpenConns(10)
eng.SetMaxIdleConns(5)
UserEng = eng
}
func MatchTokenUid(token, uid string) bool {
res, err := DB.Get([]byte(uid))
if err != nil {
fmt.Println(err)
return false
}
return string(res) == token
}
+58
View File
@@ -0,0 +1,58 @@
package db
import (
"errors"
"sync"
"github.com/syndtr/goleveldb/leveldb"
)
var (
once sync.Once
)
type Instance struct {
db *leveldb.DB
mu sync.Mutex
}
func GetInstance() *Instance {
in := Instance{}
once.Do(func() {
var err error
in.db, err = leveldb.OpenFile("./data/honoka-chan.db", nil)
if err != nil {
panic(err)
}
})
return &in
}
func (in *Instance) Close() error {
in.mu.Lock()
defer in.mu.Unlock()
if in.db != nil {
return in.db.Close()
}
return nil
}
func (in *Instance) Get(key []byte) ([]byte, error) {
if len(key) == 0 {
return nil, errors.New("empty key")
}
res, err := in.db.Get(key, nil)
if err == leveldb.ErrNotFound {
return nil, nil
} else if err != nil {
return nil, err
}
return res, nil
}
func (in *Instance) Set(key, value []byte) error {
if len(key) == 0 {
return errors.New("empty key")
}
return in.db.Put(key, value, nil)
}
+48
View File
@@ -0,0 +1,48 @@
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
)
var (
iv = []byte("12345678abcdefgh")
)
func padding(plainText []byte, blockSize int) []byte {
n := blockSize - len(plainText)%blockSize
temp := bytes.Repeat([]byte{byte(n)}, n)
plainText = append(plainText, temp...)
return plainText
}
func unPadding(cipherText []byte) []byte {
end := cipherText[len(cipherText)-1]
cipherText = cipherText[:len(cipherText)-int(end)]
return cipherText
}
func AESCBCEncrypt(plainText []byte, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
plainText = padding(plainText, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, iv)
cipherText := make([]byte, len(plainText))
blockMode.CryptBlocks(cipherText, plainText)
return cipherText
}
func AESCBCDecrypt(cipherText []byte, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
plainText := make([]byte, len(cipherText))
blockMode := cipher.NewCBCDecrypter(block, iv)
blockMode.CryptBlocks(plainText, cipherText)
plainText = unPadding(plainText)
return plainText
}
+174
View File
@@ -0,0 +1,174 @@
package encrypt
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/pem"
"honoka-chan/config"
"os"
"path/filepath"
"runtime"
)
func RSAGen(bits int) {
//get current path
_, currentpath, _, _ := runtime.Caller(0)
currentpath = filepath.Dir(currentpath)
//----------------------------------------------private key
// GenerateKey generates an RSA keypair of the given bit size using the
// random source random (for example, crypto/rand.Reader).
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
panic(err)
}
//serialize privatekey to ASN.1 der by x509.MarshalPKCS8PrivateKey
x509privatekey, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
panic(err)
}
//encode x509 to pem and save to file
//1. create privatefile
privatekeyfile, err := os.Create(config.PrivateKeyPath)
if err != nil {
panic(err)
}
defer privatekeyfile.Close()
//2. new a pem block struct object
privatekeyblock := pem.Block{
Type: "PRIVATE KEY",
Headers: nil,
Bytes: x509privatekey,
}
//3. save to file
pem.Encode(privatekeyfile, &privatekeyblock)
//----------------------------------------------public key
//get public key
publickey := privateKey.PublicKey
//serialize publickey to ASN.1 der by x509.MarshalPKCS8PublicKey
x509publickey, _ := x509.MarshalPKIXPublicKey(&publickey)
//encode x509 to pem and save to file
//1. create publickeyfile
publickeyfile, err := os.Create(config.PublicKeyPath)
if err != nil {
panic(err)
}
defer publickeyfile.Close()
//2. new a pem block struct object
publickeyblock := pem.Block{
Type: "PUBLIC KEY",
Headers: nil,
Bytes: x509publickey,
}
//3. save to file
pem.Encode(publickeyfile, &publickeyblock)
}
func RSAEncrypt(plainText []byte, publickeypath string) []byte {
//open publickeyfile
publickeyfile, err := os.Open(publickeypath)
if err != nil {
panic(err)
}
defer publickeyfile.Close()
//get publickeyfile info
publickeyfileInfo, _ := publickeyfile.Stat()
//read publickeyfile content
//1. make size
buf := make([]byte, publickeyfileInfo.Size())
//2. read file to buf
publickeyfile.Read(buf)
//3. decode pem
publickeyDecodeBlock, _ := pem.Decode(buf)
//4. x509 decode
publicKeyInterface, err := x509.ParsePKIXPublicKey(publickeyDecodeBlock.Bytes)
if err != nil {
panic(err)
}
//assert
publicKey := publicKeyInterface.(*rsa.PublicKey)
//encrypt plainText
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
if err != nil {
panic(err)
}
return cipherText
}
func RSADecrypt(cipherText []byte) []byte {
//open privatekeyfile
privatekeyfile, err := os.Open(config.PrivateKeyPath)
if err != nil {
panic(err)
}
defer privatekeyfile.Close()
//get privatekeyfile content
privatekeyinfo, _ := privatekeyfile.Stat()
buf := make([]byte, privatekeyinfo.Size())
privatekeyfile.Read(buf)
//pem decode
privatekeyblock, _ := pem.Decode(buf)
//X509 decode
parseKey, err := x509.ParsePKCS8PrivateKey(privatekeyblock.Bytes)
if err != nil {
panic(err)
}
privateKey := parseKey.(*rsa.PrivateKey)
//decrypt the cipher
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
if err != nil {
panic(err)
}
return plainText
}
func RSASignSHA1(cipherText []byte) []byte {
//open privatekeyfile
privatekeyfile, err := os.Open(config.PrivateKeyPath)
if err != nil {
panic(err)
}
defer privatekeyfile.Close()
//get privatekeyfile content
privatekeyinfo, _ := privatekeyfile.Stat()
buf := make([]byte, privatekeyinfo.Size())
privatekeyfile.Read(buf)
//pem decode
privatekeyblock, _ := pem.Decode(buf)
//X509 decode
parseKey, err := x509.ParsePKCS8PrivateKey(privatekeyblock.Bytes)
if err != nil {
panic(err)
}
privateKey := parseKey.(*rsa.PrivateKey)
msgHash := sha1.New()
_, err = msgHash.Write(cipherText)
if err != nil {
panic(err)
}
msgHashSum := msgHash.Sum(nil)
signature, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA1, msgHashSum, nil)
if err != nil {
panic(err)
}
return signature
}
+620
View File
@@ -0,0 +1,620 @@
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// The pcapdump binary implements a tcpdump-like command line tool with gopacket
// using pcap as a backend data collection mechanism.
package sifcap
import (
"bufio"
"bytes"
"compress/gzip"
"encoding/binary"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"runtime/pprof"
"strings"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/examples/util"
"github.com/google/gopacket/ip4defrag"
"github.com/google/gopacket/layers" // pulls in all layers decoders
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/reassembly"
)
var maxcount = flag.Int("c", -1, "Only grab this many packets, then exit")
var decoder = flag.String("decoder", "", "Name of the decoder to use (default: guess from capture)")
var statsevery = flag.Int("stats", 1000, "Output statistics every N packets")
var lazy = flag.Bool("lazy", false, "If true, do lazy decoding")
var nodefrag = flag.Bool("nodefrag", false, "If true, do not do IPv4 defrag")
var checksum = flag.Bool("checksum", false, "Check TCP checksum")
var nooptcheck = flag.Bool("nooptcheck", false, "Do not check TCP options (useful to ignore MSS on captures with TSO)")
var ignorefsmerr = flag.Bool("ignorefsmerr", false, "Ignore TCP FSM errors")
var allowmissinginit = flag.Bool("allowmissinginit", false, "Support streams without SYN/SYN+ACK/ACK sequence")
var verbose = flag.Bool("verbose", false, "Be verbose")
var debug = flag.Bool("debug", false, "Display debug information")
var quiet = flag.Bool("quiet", true, "Be quiet regarding errors")
// http
var nohttp = flag.Bool("nohttp", false, "Disable HTTP parsing")
var hexdump = flag.Bool("dump", false, "Dump HTTP request/response as hex")
var hexdumppkt = flag.Bool("dumppkt", false, "Dump packet as hex")
// capture
var iface = flag.String("i", "enp8s0", "Interface to read packets from")
var fname = flag.String("r", "", "Filename to read from, overrides -i")
var snaplen = flag.Int("s", 65536, "Snap length (number of bytes max to read per packet")
var tstype = flag.String("timestamp_type", "", "Type of timestamps to use")
var promisc = flag.Bool("promisc", true, "Set promiscuous mode")
var memprofile = flag.String("memprofile", "", "Write memory profile")
var stats struct {
ipdefrag int
missedBytes int
pkt int
sz int
totalsz int
rejectFsm int
rejectOpt int
rejectConnFsm int
reassembled int
outOfOrderBytes int
outOfOrderPackets int
biggestChunkBytes int
biggestChunkPackets int
overlapBytes int
overlapPackets int
}
const closeTimeout time.Duration = time.Hour * 24 // Closing inactive: TODO: from CLI
const timeout time.Duration = time.Minute * 5 // Pending bytes: TODO: from CLI
/*
* HTTP part
*/
type httpReader struct {
ident string
isClient bool
bytes chan []byte
data []byte
hexdump bool
parent *tcpStream
}
func (h *httpReader) Read(p []byte) (int, error) {
ok := true
for ok && len(h.data) == 0 {
h.data, ok = <-h.bytes
}
if !ok || len(h.data) == 0 {
return 0, io.EOF
}
l := copy(p, h.data)
h.data = h.data[l:]
return l, nil
}
var outputLevel int
var errorsMap map[string]uint
var errorsMapMutex sync.Mutex
var errors uint
// Too bad for perf that a... is evaluated
func Error(t string, s string, a ...any) {
errorsMapMutex.Lock()
errors++
errorsMap[t] = errorsMap[t] + 1
errorsMapMutex.Unlock()
if outputLevel >= 0 {
fmt.Printf(s, a...)
}
}
func Info(s string, a ...any) {
if outputLevel >= 1 {
fmt.Printf(s, a...)
}
}
func Debug(s string, a ...any) {
if outputLevel >= 2 {
fmt.Printf(s, a...)
}
}
func (h *httpReader) run(wg *sync.WaitGroup) {
defer wg.Done()
b := bufio.NewReader(h)
for {
if h.isClient {
req, err := http.ReadRequest(b)
if err == io.EOF || err == io.ErrUnexpectedEOF {
break
} else if err != nil {
Error("HTTP-request", "HTTP/%s Request error: %s (%v,%+v)\n", h.ident, err, err, err)
continue
}
body, err := io.ReadAll(req.Body)
s := len(body)
if err != nil {
Error("HTTP-request-body", "Got body err: %s\n", err)
} else if h.hexdump {
Info("Body(%d/0x%x)\n%s\n", len(body), len(body), hex.Dump(body))
}
req.Body.Close()
Info("HTTP/%s Request: %s %s (body:%d)\n", h.ident, req.Method, req.URL, s)
h.parent.Lock()
h.parent.urls = append(h.parent.urls, req.URL.String())
h.parent.Unlock()
} else {
res, err := http.ReadResponse(b, nil)
var req string
h.parent.Lock()
if len(h.parent.urls) == 0 {
req = "<no-request-seen>"
} else {
req, h.parent.urls = h.parent.urls[0], h.parent.urls[1:]
}
h.parent.Unlock()
if err == io.EOF || err == io.ErrUnexpectedEOF {
break
} else if err != nil {
Error("HTTP-response", "HTTP/%s Response error: %s (%v,%+v)\n", h.ident, err, err, err)
continue
}
body, _ := io.ReadAll(res.Body)
s := len(body)
if err != nil {
Error("HTTP-response-body", "HTTP/%s: failed to get body(parsed len:%d): %s\n", h.ident, s, err)
}
if h.hexdump {
Info("Body(%d/0x%x)\n%s\n", len(body), len(body), hex.Dump(body))
}
res.Body.Close()
sym := ","
if res.ContentLength > 0 && res.ContentLength != int64(s) {
sym = "!="
}
contentType, ok := res.Header["Content-Type"]
if !ok {
contentType = []string{http.DetectContentType(body)}
}
encoding := res.Header["Content-Encoding"]
Info("HTTP/%s Response: %s URL:%s (%d%s%d%s) -> %s\n", h.ident, res.Status, req, res.ContentLength, sym, s, contentType, encoding[0])
if err == nil {
var r io.Reader
r = bytes.NewBuffer(body)
if len(encoding) > 0 && (encoding[0] == "gzip" || encoding[0] == "deflate") {
r, err = gzip.NewReader(r)
if err != nil {
Error("HTTP-gunzip", "Failed to gzip decode: %s", err)
}
}
if err == nil {
res, _ := io.ReadAll(r)
fmt.Println(string(res))
}
}
}
}
}
/*
* The TCP factory: returns a new Stream
*/
type tcpStreamFactory struct {
wg sync.WaitGroup
doHTTP bool
}
func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream {
Debug("* NEW: %s %s\n", net, transport)
fsmOptions := reassembly.TCPSimpleFSMOptions{
SupportMissingEstablishment: *allowmissinginit,
}
stream := &tcpStream{
net: net,
transport: transport,
isDNS: tcp.SrcPort == 53 || tcp.DstPort == 53,
isHTTP: (tcp.SrcPort == 80 || tcp.DstPort == 80) && factory.doHTTP,
reversed: tcp.SrcPort == 80,
tcpstate: reassembly.NewTCPSimpleFSM(fsmOptions),
ident: fmt.Sprintf("%s:%s", net, transport),
optchecker: reassembly.NewTCPOptionCheck(),
}
if stream.isHTTP {
stream.client = httpReader{
bytes: make(chan []byte),
ident: fmt.Sprintf("%s %s", net, transport),
hexdump: *hexdump,
parent: stream,
isClient: true,
}
stream.server = httpReader{
bytes: make(chan []byte),
ident: fmt.Sprintf("%s %s", net.Reverse(), transport.Reverse()),
hexdump: *hexdump,
parent: stream,
}
factory.wg.Add(2)
go stream.client.run(&factory.wg)
go stream.server.run(&factory.wg)
}
return stream
}
func (factory *tcpStreamFactory) WaitGoRoutines() {
factory.wg.Wait()
}
/*
* The assembler context
*/
type Context struct {
CaptureInfo gopacket.CaptureInfo
}
func (c *Context) GetCaptureInfo() gopacket.CaptureInfo {
return c.CaptureInfo
}
/*
* TCP stream
*/
/* It's a connection (bidirectional) */
type tcpStream struct {
tcpstate *reassembly.TCPSimpleFSM
fsmerr bool
optchecker reassembly.TCPOptionCheck
net, transport gopacket.Flow
isDNS bool
isHTTP bool
reversed bool
client httpReader
server httpReader
urls []string
ident string
sync.Mutex
}
func (t *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool {
// FSM
if !t.tcpstate.CheckState(tcp, dir) {
Error("FSM", "%s: Packet rejected by FSM (state:%s)\n", t.ident, t.tcpstate.String())
stats.rejectFsm++
if !t.fsmerr {
t.fsmerr = true
stats.rejectConnFsm++
}
if !*ignorefsmerr {
return false
}
}
// Options
err := t.optchecker.Accept(tcp, ci, dir, nextSeq, start)
if err != nil {
Error("OptionChecker", "%s: Packet rejected by OptionChecker: %s\n", t.ident, err)
stats.rejectOpt++
if !*nooptcheck {
return false
}
}
// Checksum
accept := true
if *checksum {
c, err := tcp.ComputeChecksum()
if err != nil {
Error("ChecksumCompute", "%s: Got error computing checksum: %s\n", t.ident, err)
accept = false
} else if c != 0x0 {
Error("Checksum", "%s: Invalid checksum: 0x%x\n", t.ident, c)
accept = false
}
}
if !accept {
stats.rejectOpt++
}
return accept
}
func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) {
dir, start, end, skip := sg.Info()
length, saved := sg.Lengths()
// update stats
sgStats := sg.Stats()
if skip > 0 {
stats.missedBytes += skip
}
stats.sz += length - saved
stats.pkt += sgStats.Packets
if sgStats.Chunks > 1 {
stats.reassembled++
}
stats.outOfOrderPackets += sgStats.QueuedPackets
stats.outOfOrderBytes += sgStats.QueuedBytes
if length > stats.biggestChunkBytes {
stats.biggestChunkBytes = length
}
if sgStats.Packets > stats.biggestChunkPackets {
stats.biggestChunkPackets = sgStats.Packets
}
if sgStats.OverlapBytes != 0 && sgStats.OverlapPackets == 0 {
fmt.Printf("bytes:%d, pkts:%d\n", sgStats.OverlapBytes, sgStats.OverlapPackets)
panic("Invalid overlap")
}
stats.overlapBytes += sgStats.OverlapBytes
stats.overlapPackets += sgStats.OverlapPackets
var ident string
if dir == reassembly.TCPDirClientToServer {
ident = fmt.Sprintf("%v %v(%s): ", t.net, t.transport, dir)
} else {
ident = fmt.Sprintf("%v %v(%s): ", t.net.Reverse(), t.transport.Reverse(), dir)
}
Debug("%s: SG reassembled packet with %d bytes (start:%v,end:%v,skip:%d,saved:%d,nb:%d,%d,overlap:%d,%d)\n", ident, length, start, end, skip, saved, sgStats.Packets, sgStats.Chunks, sgStats.OverlapBytes, sgStats.OverlapPackets)
if skip == -1 && *allowmissinginit {
// this is allowed
} else if skip != 0 {
// Missing bytes in stream: do not even try to parse it
return
}
data := sg.Fetch(length)
if t.isDNS {
dns := &layers.DNS{}
var decoded []gopacket.LayerType
if len(data) < 2 {
if len(data) > 0 {
sg.KeepFrom(0)
}
return
}
dnsSize := binary.BigEndian.Uint16(data[:2])
missing := int(dnsSize) - len(data[2:])
Debug("dnsSize: %d, missing: %d\n", dnsSize, missing)
if missing > 0 {
Info("Missing some bytes: %d\n", missing)
sg.KeepFrom(0)
return
}
p := gopacket.NewDecodingLayerParser(layers.LayerTypeDNS, dns)
err := p.DecodeLayers(data[2:], &decoded)
if err != nil {
Error("DNS-parser", "Failed to decode DNS: %v\n", err)
} else {
Debug("DNS: %s\n", gopacket.LayerDump(dns))
}
if len(data) > 2+int(dnsSize) {
sg.KeepFrom(2 + int(dnsSize))
}
} else if t.isHTTP {
if length > 0 {
if *hexdump {
Debug("Feeding http with:\n%s", hex.Dump(data))
}
if dir == reassembly.TCPDirClientToServer && !t.reversed {
t.client.bytes <- data
} else {
t.server.bytes <- data
}
}
}
}
func (t *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
Debug("%s: Connection closed\n", t.ident)
if t.isHTTP {
close(t.client.bytes)
close(t.server.bytes)
}
// do not remove the connection to allow last ACK
return false
}
func Start() {
defer util.Run()()
var handle *pcap.Handle
var err error
if *debug {
outputLevel = 2
} else if *verbose {
outputLevel = 1
} else if *quiet {
outputLevel = -1
}
errorsMap = make(map[string]uint)
if *fname != "" {
if handle, err = pcap.OpenOffline(*fname); err != nil {
log.Fatal("PCAP OpenOffline error:", err)
}
} else {
// This is a little complicated because we want to allow all possible options
// for creating the packet capture handle... instead of all this you can
// just call pcap.OpenLive if you want a simple handle.
inactive, err := pcap.NewInactiveHandle(*iface)
if err != nil {
log.Fatalf("could not create: %v", err)
}
defer inactive.CleanUp()
if err = inactive.SetSnapLen(*snaplen); err != nil {
log.Fatalf("could not set snap length: %v", err)
} else if err = inactive.SetPromisc(*promisc); err != nil {
log.Fatalf("could not set promisc mode: %v", err)
} else if err = inactive.SetTimeout(time.Second); err != nil {
log.Fatalf("could not set timeout: %v", err)
}
if *tstype != "" {
if t, err := pcap.TimestampSourceFromString(*tstype); err != nil {
log.Fatalf("Supported timestamp types: %v", inactive.SupportedTimestamps())
} else if err := inactive.SetTimestampSource(t); err != nil {
log.Fatalf("Supported timestamp types: %v", inactive.SupportedTimestamps())
}
}
if handle, err = inactive.Activate(); err != nil {
log.Fatal("PCAP Activate error:", err)
}
defer handle.Close()
}
if len(flag.Args()) > 0 {
bpffilter := strings.Join(flag.Args(), " ")
Info("Using BPF filter %q\n", bpffilter)
if err = handle.SetBPFFilter(bpffilter); err != nil {
log.Fatal("BPF filter error:", err)
}
}
var dec gopacket.Decoder
var ok bool
decoder_name := *decoder
if decoder_name == "" {
decoder_name = handle.LinkType().String()
}
if dec, ok = gopacket.DecodersByLayerName[decoder_name]; !ok {
log.Fatalln("No decoder named", decoder_name)
}
source := gopacket.NewPacketSource(handle, dec)
source.Lazy = *lazy
source.NoCopy = true
Info("Starting to read packets\n")
count := 0
bytes := int64(0)
start := time.Now()
defragger := ip4defrag.NewIPv4Defragmenter()
streamFactory := &tcpStreamFactory{doHTTP: !*nohttp}
streamPool := reassembly.NewStreamPool(streamFactory)
assembler := reassembly.NewAssembler(streamPool)
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
for packet := range source.Packets() {
count++
Debug("PACKET #%d\n", count)
data := packet.Data()
bytes += int64(len(data))
if *hexdumppkt {
Debug("Packet content (%d/0x%x)\n%s\n", len(data), len(data), hex.Dump(data))
}
// defrag the IPv4 packet if required
if !*nodefrag {
ip4Layer := packet.Layer(layers.LayerTypeIPv4)
if ip4Layer == nil {
continue
}
ip4 := ip4Layer.(*layers.IPv4)
l := ip4.Length
newip4, err := defragger.DefragIPv4(ip4)
if err != nil {
log.Fatalln("Error while de-fragmenting", err)
} else if newip4 == nil {
Debug("Fragment...\n")
continue // packet fragment, we don't have whole packet yet.
}
if newip4.Length != l {
stats.ipdefrag++
Debug("Decoding re-assembled packet: %s\n", newip4.NextLayerType())
pb, ok := packet.(gopacket.PacketBuilder)
if !ok {
panic("Not a PacketBuilder")
}
nextDecoder := newip4.NextLayerType()
nextDecoder.Decode(newip4.Payload, pb)
}
}
tcp := packet.Layer(layers.LayerTypeTCP)
if tcp != nil {
tcp := tcp.(*layers.TCP)
if *checksum {
err := tcp.SetNetworkLayerForChecksum(packet.NetworkLayer())
if err != nil {
log.Fatalf("Failed to set network layer for checksum: %s\n", err)
}
}
c := Context{
CaptureInfo: packet.Metadata().CaptureInfo,
}
stats.totalsz += len(tcp.Payload)
assembler.AssembleWithContext(packet.NetworkLayer().NetworkFlow(), tcp, &c)
}
if count%*statsevery == 0 {
ref := packet.Metadata().CaptureInfo.Timestamp
flushed, closed := assembler.FlushWithOptions(reassembly.FlushOptions{T: ref.Add(-timeout), TC: ref.Add(-closeTimeout)})
Debug("Forced flush: %d flushed, %d closed (%s)", flushed, closed, ref)
}
done := *maxcount > 0 && count >= *maxcount
if count%*statsevery == 0 || done {
errorsMapMutex.Lock()
errorMapLen := len(errorsMap)
errorsMapMutex.Unlock()
fmt.Fprintf(os.Stderr, "Processed %v packets (%v bytes) in %v (errors: %v, errTypes:%v)\n", count, bytes, time.Since(start), errors, errorMapLen)
}
select {
case <-signalChan:
fmt.Fprintf(os.Stderr, "\nCaught SIGINT: aborting\n")
done = true
default:
// NOP: continue
}
if done {
break
}
}
closed := assembler.FlushAll()
Debug("Final flush: %d closed", closed)
if outputLevel >= 2 {
streamPool.Dump()
}
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal(err)
}
pprof.WriteHeapProfile(f)
f.Close()
}
streamFactory.WaitGoRoutines()
Debug("%s\n", assembler.Dump())
if !*nodefrag {
fmt.Printf("IPdefrag:\t\t%d\n", stats.ipdefrag)
}
fmt.Printf("TCP stats:\n")
fmt.Printf(" missed bytes:\t\t%d\n", stats.missedBytes)
fmt.Printf(" total packets:\t\t%d\n", stats.pkt)
fmt.Printf(" rejected FSM:\t\t%d\n", stats.rejectFsm)
fmt.Printf(" rejected Options:\t%d\n", stats.rejectOpt)
fmt.Printf(" reassembled bytes:\t%d\n", stats.sz)
fmt.Printf(" total TCP bytes:\t%d\n", stats.totalsz)
fmt.Printf(" conn rejected FSM:\t%d\n", stats.rejectConnFsm)
fmt.Printf(" reassembled chunks:\t%d\n", stats.reassembled)
fmt.Printf(" out-of-order packets:\t%d\n", stats.outOfOrderPackets)
fmt.Printf(" out-of-order bytes:\t%d\n", stats.outOfOrderBytes)
fmt.Printf(" biggest-chunk packets:\t%d\n", stats.biggestChunkPackets)
fmt.Printf(" biggest-chunk bytes:\t%d\n", stats.biggestChunkBytes)
fmt.Printf(" overlap packets:\t%d\n", stats.overlapPackets)
fmt.Printf(" overlap bytes:\t\t%d\n", stats.overlapBytes)
fmt.Printf("Errors: %d\n", errors)
for e := range errorsMap {
fmt.Printf(" %s:\t\t%d\n", e, errorsMap[e])
}
}
+61
View File
@@ -0,0 +1,61 @@
// Copyright (C) 2021-2023 YumeMichi
//
// SPDX-License-Identifier: Apache-2.0
package utils
import (
"encoding/hex"
"math/rand"
"os"
"sync"
"time"
)
var (
rwMutex sync.RWMutex
)
func PathExists(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
func ReadAllText(path string) string {
rwMutex.RLock()
defer rwMutex.RUnlock()
b, err := os.ReadFile(path)
if err != nil {
return ""
}
return string(b)
}
func WriteAllText(path, text string) {
rwMutex.Lock()
defer rwMutex.Unlock()
_ = os.WriteFile(path, []byte(text), 0644)
}
func SliceXor(s1, s2 []byte) (res []byte) {
for k, b := range s1 {
newBt := b ^ s2[k]
res = append(res, newBt)
}
return
}
func Sub16(str []byte) []byte {
return str[16:]
}
func RandomStr(len int) string {
rand.Seed(time.Now().UnixNano())
mRand := make([]byte, len)
rand.Read(mRand)
mRandStr := hex.EncodeToString(mRand)[0:len]
return mRandStr
}