Skip to content

Commit

Permalink
refactor + fix hash function
Browse files Browse the repository at this point in the history
  • Loading branch information
alessio-perugini committed May 10, 2020
1 parent f1cac10 commit 63d4e50
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 84 deletions.
77 changes: 76 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,80 @@
package main

import (
"flag"
"fmt"
p "github.com/alessio-perugini/peng"
"log"
"net/url"
"os"
)

var (
config = p.Config{
NumberOfBin: 8,
NumberOfModule: 1024,
InfluxUrl: "http://localhost",
InfluxPort: 9999,
InfluxBucket: "",
InfluxOrganization: "",
InfluxAuthToken: "",
}

versionFlag bool
version = "0.0.0"
commit = "commithash"
)

func init() {
//Bitmap
flag.UintVar(&config.InfluxPort, "bin", 128, "number of bin in your bitmap")
flag.UintVar(&config.InfluxPort, "module", 1024, "maximum size of your bitmap")

//influx
flag.StringVar(&config.InfluxUrl, "influxUrl", "http://localhost", "influx url")
flag.UintVar(&config.InfluxPort, "influxPort", 9999, "influxPort number")
flag.StringVar(&config.InfluxBucket, "bucket", "", "bucket string for telegraf")
flag.StringVar(&config.InfluxOrganization, "org", "", "organization string for telegraf")
flag.StringVar(&config.InfluxAuthToken, "token", "", "auth token for influxdb")

//other
flag.BoolVar(&versionFlag, "version", false, "output version")
}

func flagConfig() {
appString := fmt.Sprintf("sys-status version %s %s", version, commit)

flag.Usage = func() { //help flag
fmt.Fprintf(flag.CommandLine.Output(), "%s\n\nUsage: sys-status [options]\n", appString)
flag.PrintDefaults()
}

flag.Parse()

if versionFlag { //version flag
fmt.Fprintf(flag.CommandLine.Output(), "%s\n", appString)
os.Exit(2)
}

if config.InfluxBucket == "" || config.InfluxOrganization == "" || config.InfluxAuthToken == "" {
log.Fatal("You must provide bucket, organization and influxAuthToken")
}

if _, err := url.ParseRequestURI(config.InfluxUrl); err != nil {
log.Fatal("Influx url is not valid")
}

fmt.Printf("%s\n", appString)
}

func main() {

flagConfig()

peng := p.New(&config)
peng.Portbitmap.HashFunc = func(port uint16) (uint16, uint64) {
portModuled := (port / uint16(config.NumberOfBin)) % uint16(config.NumberOfModule)
index, bit := portModuled/uint16(config.NumberOfBits), uint64(portModuled)%uint64(config.NumberOfBits)
return index, bit
}
peng.Start()
}
146 changes: 63 additions & 83 deletions peng.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package main
package peng

import (
"errors"
"flag"
"fmt"
b "github.com/alessio-perugini/peng/pkg/bitmap"
"github.com/alessio-perugini/peng/pkg/portbitmap"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
_ "github.com/google/gopacket/layers" //Used to init internal struct
Expand All @@ -18,42 +16,50 @@ import (
"time"
)

//Clear bit &= ^flag
//ToggleFlag ^= flag
type Peng struct {
Config *Config
Portbitmap *portbitmap.PortBitmap
}

type Config struct {
NumberOfBin uint //TODO forse rimuovere i 2 campi e usare la config del portbitmap
NumberOfModule uint
NumberOfBits uint
InfluxUrl string
InfluxPort uint
InfluxBucket string
InfluxOrganization string
InfluxAuthToken string
}

var (
nBin = 128
nModule = 1024
nBits = uint(nModule / nBin)
bitmap = make([]b.Bitmap, nBin)
myIPs = make([]net.IP, 0, 2)
epsilon = math.Nextafter(1.0, 2.0) - 1.0

influxUrl string
bucket string
organization string
influxPort uint
influxAuthToken string
)

//TODO influxdb stuff
func main() {
flag.StringVar(&influxUrl, "influxUrl", "http://localhost", "influx url")
flag.UintVar(&influxPort, "influxPort", 9999, "influxPort number")
flag.StringVar(&bucket, "bucket", "", "bucket string for telegraf")
flag.StringVar(&organization, "org", "", "organization string for telegraf")
flag.StringVar(&influxAuthToken, "token", "", "auth token for influxdb")
flag.Parse()
func New(cfg *Config) *Peng {
cfg.NumberOfBits = cfg.NumberOfModule / cfg.NumberOfBin
bitmapConfig := &portbitmap.Config{
NumberOfBin: cfg.NumberOfBin,
SizeBitmap: cfg.NumberOfModule,
NumberOfBits: cfg.NumberOfBits,
}

GetMyIp()
initBitmap()
return &Peng{
Config: cfg,
Portbitmap: portbitmap.New(bitmapConfig),
}
}

func (p *Peng) Start() {
getMyIp()

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Println(sig)
fmt.Println(bitmap)
fmt.Println(p.Portbitmap.InnerBitmap)
os.Exit(1)
}
}()
Expand All @@ -71,62 +77,34 @@ func main() {

packet := gopacket.NewPacketSource(pHandle, pHandle.LinkType())

time.AfterFunc(time.Minute, End)
time.AfterFunc(time.Minute, p.end)
for packet := range packet.Packets() {
inspect(packet)
p.inspect(packet)
//TODO multithread?
//TODO proper handle termination
//TODO maybe use custom layers to avoid realloc for each packets (memory improvment)
//TODo maybe spawn goroutine foreach bitmap?
}
}

func initBitmap() {
//Create bitmap
for i := 0; i < nBin; i++ {
bitmap[i] = *b.New(uint64(nBits))
}
}

func hash(port uint16) (uint16, uint64) {
portModuled := port % uint16(nModule)
index, bit := portModuled/uint16(nBits), uint64(portModuled)%uint64(nBits)
return index, bit
}

func InsertInBitmap(port uint16) error {
indexBin, bitBin := hash(port)
if indexBin >= uint16(len(bitmap)) {
return errors.New("index to access the bin is invalid")
}
bitmap[indexBin].SetBit(bitBin, true)
return nil
}

func ResetBitmap() {
for i := 0; i < len(bitmap); i++ {
bitmap[i].ResetAllBits()
}
}

func EntropyTotal(binsEntropy []float64) float64 {
func (p *Peng) EntropyTotal(binsEntropy []float64) float64 {
var totalEntropy float64
for _, v := range binsEntropy {
totalEntropy += v
}

return totalEntropy / float64(nBin)
return totalEntropy / float64(p.Portbitmap.Config.NumberOfBin)
}

//reference https://rosettacode.org/wiki/Entropy
func EntropyOfEachBin() []float64 {
var total = float64(nBits) //number of bits in the bin
var sum float64 //used to compute the entropy
allEntropy := make([]float64, 0, nBin) //used to calculate entropy of each bin
func (p *Peng) EntropyOfEachBin() []float64 {
var total = float64(p.Portbitmap.Config.NumberOfBits) //number of bits in the bin
var sum float64 //used to compute the entropy
allEntropy := make([]float64, 0, p.Portbitmap.Config.NumberOfBin) //used to calculate entropy of each bin

for i := 0; i < len(bitmap); i++ {
bitsAt1 := float64(bitmap[i].GetBitSets()) / total
bitsAt0 := float64(uint64(nBits)-bitmap[i].GetBitSets()) / total
for i := 0; i < len(p.Portbitmap.InnerBitmap); i++ {
bitsAt1 := float64(p.Portbitmap.InnerBitmap[i].GetBitSets()) / total
bitsAt0 := float64(uint64(p.Portbitmap.Config.NumberOfBits)-p.Portbitmap.InnerBitmap[i].GetBitSets()) / total

if bitsAt1 > epsilon && bitsAt0 > epsilon {
sum -= bitsAt1 * math.Log(bitsAt1)
Expand All @@ -145,24 +123,24 @@ func EntropyOfEachBin() []float64 {
return allEntropy
}

func End() {
fmt.Println(bitmap)
func (p *Peng) end() {
fmt.Println(p.Portbitmap)
fmt.Println("Bit set: ")
for i := 0; i < len(bitmap); i++ {
fmt.Println("pos [", i, "] num: ", bitmap[i].GetBitSets())
for i := 0; i < len(p.Portbitmap.InnerBitmap); i++ {
fmt.Println("pos [", i, "] num: ", p.Portbitmap.InnerBitmap[i].GetBitSets())
}

binsEntropy := EntropyOfEachBin()
totalEntropy := EntropyTotal(binsEntropy)
PushToInfluxDb("server", totalEntropy, binsEntropy, time.Minute) //TODO generalizzare meglio
binsEntropy := p.EntropyOfEachBin()
totalEntropy := p.EntropyTotal(binsEntropy)
p.PushToInfluxDb("server", totalEntropy, binsEntropy, time.Minute) //TODO generalizzare meglio
fmt.Println("EntropyOfEachBin: ", binsEntropy)
fmt.Println("EntropyTotal: ", totalEntropy)

ResetBitmap()
p.Portbitmap.ClearAll()
os.Exit(1)
}

func GetMyIp() {
func getMyIp() {
addrs, err := net.InterfaceAddrs()
if err != nil {
log.Fatal(err.Error())
Expand All @@ -178,7 +156,7 @@ func GetMyIp() {
}
}

func inspect(packet gopacket.Packet) {
func (p *Peng) inspect(packet gopacket.Packet) {
var ipv4Layer gopacket.Layer //skip inspection if i can't obtain ip layer
if ipv4Layer = packet.Layer(layers.LayerTypeIPv4); ipv4Layer == nil {
return
Expand All @@ -204,16 +182,19 @@ func inspect(packet gopacket.Packet) {
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
if tcp.SYN {
InsertInBitmap(uint16(tcp.DstPort))
err := p.Portbitmap.AddPort(uint16(tcp.DstPort))
if err != nil {
log.Println(err.Error())
}
}
}
}

//TODO generalizzare meglio
func PushToInfluxDb(typeName string, totalEntropy float64, binsEntropy []float64, interval time.Duration) {
client := influxdb2.NewClient(influxUrl+":"+fmt.Sprint(influxPort), influxAuthToken)
func (p *Peng) PushToInfluxDb(typeName string, totalEntropy float64, binsEntropy []float64, interval time.Duration) {
client := influxdb2.NewClient(p.Config.InfluxUrl+":"+fmt.Sprint(p.Config.InfluxPort), p.Config.InfluxAuthToken)
defer client.Close()
writeApi := client.WriteApi(organization, bucket) //non-blocking
writeApi := client.WriteApi(p.Config.InfluxOrganization, p.Config.InfluxBucket) //non-blocking

//Create fields to send to influx
influxFields := make(map[string]interface{}, len(binsEntropy)+2)
Expand All @@ -225,16 +206,15 @@ func PushToInfluxDb(typeName string, totalEntropy float64, binsEntropy []float64
influxFields["total_entropy"] = totalEntropy

//Send point of system with hostname and values about in and out bits
p := influxdb2.NewPoint(
point := influxdb2.NewPoint(
"entropy",
map[string]string{
"type": typeName,
},
influxFields,
time.Now())

writeApi.WritePoint(p)
writeApi.WritePoint(point)

writeApi.Flush() // Force all unwritten data to be sent

}
55 changes: 55 additions & 0 deletions pkg/portbitmap/portbitmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package portbitmap

import (
"errors"
b "github.com/alessio-perugini/peng/pkg/bitmap"
)

type PortBitmap struct {
Config *Config
InnerBitmap []b.Bitmap
HashFunc func(port uint16) (uint16, uint64)
}

type Config struct {
NumberOfBin uint
SizeBitmap uint
NumberOfBits uint
}

//TODO levare il puntatore a config
func New(cfg *Config) *PortBitmap {
var InnerBitmap = make([]b.Bitmap, cfg.NumberOfBin)
cfg.NumberOfBits = cfg.SizeBitmap / cfg.NumberOfBin

for i := 0; i < int(cfg.NumberOfBin); i++ {
InnerBitmap[i] = *b.New(uint64(cfg.NumberOfBits))
}

var hashFunc = func(port uint16) (uint16, uint64) {
portModuled := port % uint16(cfg.SizeBitmap)
index, bit := portModuled/uint16(cfg.NumberOfBits), uint64(portModuled)%uint64(cfg.NumberOfBits)
return index, bit
}

return &PortBitmap{
InnerBitmap: InnerBitmap,
HashFunc: hashFunc,
Config: cfg,
}
}

func (p *PortBitmap) AddPort(port uint16) error {
indexBin, bitBin := p.HashFunc(port)
if indexBin >= uint16(len(p.InnerBitmap)) {
return errors.New("index to access the bin is invalid")
}
p.InnerBitmap[indexBin].SetBit(bitBin, true)
return nil
}

func (p *PortBitmap) ClearAll() {
for i := 0; i < len(p.InnerBitmap); i++ {
p.InnerBitmap[i].ResetAllBits()
}
}

0 comments on commit 63d4e50

Please sign in to comment.