Skip to content

Commit

Permalink
Merge pull request #279 from sipcapture/lua_script
Browse files Browse the repository at this point in the history
Lua script
  • Loading branch information
adubovikov committed Mar 12, 2024
2 parents 8c1057a + 860871a commit e942481
Show file tree
Hide file tree
Showing 17 changed files with 3,004 additions and 6 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ jobs:
go-version: 1.21

- name: Libraries
run: sudo apt-get install -y libpcap-dev
run: sudo apt-get install -y libpcap-dev libluajit-5.1-dev

- name: LuaJIT
run: git clone https://luajit.org/git/luajit-2.0.git && cd luajit-2.0 && make CCOPT="-static -fPIC" BUILDMODE="static" && sudo make install

- name: Build
run: go build -ldflags "-s -w" -o heplify *.go
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,35 @@ Download [heplify.exe](https://github.com/sipcapture/heplify/releases)

If you have Go 1.18+ installed, build the latest heplify binary by running `make`.

Now you should install LUA Jit:

* Compile from sources:

Install luajit dev libary

`apt-get install libluajit-5.1-dev`

or

`yum install luajit-devel`

or for macOS

```sh
# Assuming brew installs to /usr/local/
brew install lua@5.1 luajit
ln -s /usr/local/lib/pkgconfig/luajit.pc /usr/local/lib/pkgconfig/luajit-5.1.pc
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/
```

[install](https://golang.org/doc/install) Go 1.11+

`go build cmd/heplify/heplify.go`





You can also build a docker image:

```bash
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type Config struct {
SendRetries uint
KeepAlive uint
Version bool
ScriptFile string
ScriptHEPFilter []int
SkipVerify bool
HEPBufferDebug bool
HEPBufferEnable bool
Expand Down
98 changes: 97 additions & 1 deletion decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import (
"bytes"
"container/list"
"net"
"reflect"
"strconv"
"strings"
"sync/atomic"
"time"
"unsafe"

"github.com/VictoriaMetrics/fastcache"
"github.com/segmentio/encoding/json"

"github.com/google/gopacket"
Expand All @@ -24,7 +27,10 @@ import (
"github.com/sipcapture/heplify/protos"
)

var PacketQueue = make(chan *Packet, 20000)
var (
PacketQueue = make(chan *Packet, 20000)
scriptCache = fastcache.New(32 * 1024 * 1024)
)

type CachePayload struct {
SrcIP net.IP `json:"src_ip" default:""`
Expand Down Expand Up @@ -1074,3 +1080,93 @@ func (d *Decoder) SendPingHEPPacket() {

PacketQueue <- pkt
}

func stb(s string) []byte {
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
var res []byte

bh := (*reflect.SliceHeader)((unsafe.Pointer(&res)))
bh.Data = sh.Data
bh.Len = sh.Len
bh.Cap = sh.Len
return res
}

// Packet
func (pkt *Packet) GetVersion() uint32 {
if pkt != nil {
return uint32(pkt.Version)
}
return 0
}

func (pkt *Packet) GetProtocol() uint32 {
if pkt != nil {
return uint32(pkt.Protocol)
}
return 0
}

func (pkt *Packet) GetSrcIP() string {
if pkt != nil {
return pkt.SrcIP.String()
}
return ""
}

func (pkt *Packet) GetDstIP() string {
if pkt != nil {
return pkt.DstIP.String()
}
return ""
}

func (pkt *Packet) GetSrcPort() uint16 {
if pkt != nil {
return pkt.SrcPort
}

return 0
}

func (pkt *Packet) GetDstPort() uint16 {
if pkt != nil {
return pkt.DstPort
}
return 0
}

func (pkt *Packet) GetTsec() uint32 {
if pkt != nil {
return pkt.Tsec
}
return 0
}

func (pkt *Packet) GetTmsec() uint32 {
if pkt != nil {
return pkt.Tmsec
}
return 0
}

func (pkt *Packet) GetProtoType() uint32 {
if pkt != nil {
return uint32(pkt.ProtoType)
}
return 0
}

func (pkt *Packet) GetPayload() string {
if pkt != nil {
return string(pkt.Payload)
}
return ""
}

func (pkt *Packet) GetCID() string {
if pkt != nil {
return string(pkt.CID)
}
return ""
}
162 changes: 162 additions & 0 deletions decoder/luaengine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package decoder

import (
"fmt"
"net"
"strconv"

"github.com/negbie/logp"
"github.com/sipcapture/golua/lua"
"github.com/sipcapture/heplify/decoder/luar"
)

// LuaEngine
type LuaEngine struct {
/* pointer to modify */
pkt **Packet
functions []string
LuaEngine *lua.State
}

func (d *LuaEngine) GetHEPProtoType() uint32 {
return (*d.pkt).GetProtoType()
}

func (d *LuaEngine) GetHEPSrcIP() string {
return (*d.pkt).GetSrcIP()
}

func (d *LuaEngine) GetHEPSrcPort() uint16 {
return (*d.pkt).GetSrcPort()
}

func (d *LuaEngine) GetHEPDstIP() string {
return (*d.pkt).GetDstIP()
}

func (d *LuaEngine) GetHEPDstPort() uint16 {
return (*d.pkt).GetDstPort()
}

func (d *LuaEngine) GetHEPTimeSeconds() uint32 {
return (*d.pkt).GetTsec()
}

func (d *LuaEngine) GetHEPTimeUseconds() uint32 {
return (*d.pkt).GetTmsec()
}

func (d *LuaEngine) GetRawMessage() string {
return (*d.pkt).GetPayload()
}

func (d *LuaEngine) SetRawMessage(value string) {
if (*d.pkt) == nil {
logp.Err("can't set Raw message if HEP struct is nil, please check for nil in lua script")
return
}
pkt := *d.pkt
pkt.Payload = []byte(value)
}

func (d *LuaEngine) SetHEPField(field string, value string) {
if (*d.pkt) == nil {
logp.Err("can't set HEP field if HEP struct is nil, please check for nil in lua script")
return
}
pkt := *d.pkt

switch field {
case "ProtoType":
if i, err := strconv.Atoi(value); err == nil {
pkt.ProtoType = byte(i)
}
case "SrcIP":
pkt.SrcIP = net.ParseIP(value).To4()
case "SrcPort":
if i, err := strconv.Atoi(value); err == nil {
pkt.SrcPort = uint16(i)
}
case "DstIP":
pkt.DstIP = net.ParseIP(value).To4()
case "DstPort":
if i, err := strconv.Atoi(value); err == nil {
pkt.DstPort = uint16(i)
}

case "CID":
pkt.CID = []byte(value)

}
}

func (d *LuaEngine) Logp(level string, message string, data interface{}) {
if level == "ERROR" {
logp.Err("[script] %s: %v", message, data)
} else {
logp.Debug("[script] %s: %v", message, data)
}
}

func (d *LuaEngine) Close() {
d.LuaEngine.Close()
}

// NewLuaEngine returns the script engine struct
func NewLuaEngine() (*LuaEngine, error) {
logp.Debug("script", "register Lua engine")

d := &LuaEngine{}
d.LuaEngine = lua.NewState()
d.LuaEngine.OpenLibs()

luar.Register(d.LuaEngine, "", luar.Map{
"GetHEPProtoType": d.GetHEPProtoType,
"GetHEPSrcIP": d.GetHEPSrcIP,
"GetHEPSrcPort": d.GetHEPSrcPort,
"GetHEPDstIP": d.GetHEPDstIP,
"GetHEPDstPort": d.GetHEPDstPort,
"GetHEPTimeSeconds": d.GetHEPTimeSeconds,
"GetHEPTimeUseconds": d.GetHEPTimeUseconds,
"GetRawMessage": d.GetRawMessage,
"SetRawMessage": d.SetRawMessage,
"SetHEPField": d.SetHEPField,
"HashTable": HashTable,
"HashString": HashString,
"Logp": d.Logp,
"Print": fmt.Println,
})

_, code, err := scanCode()
if err != nil {
logp.Err("Error in scan script: %v", err)
return nil, err
}

err = d.LuaEngine.DoString(code.String())
if err != nil {
logp.Err("Error in lua script: %v", err)
return nil, err
}

d.functions = extractFunc(code)
if len(d.functions) < 1 {
logp.Err("no function name found in lua scripts: %v", err)
return nil, fmt.Errorf("no function name found in lua scripts")
}

return d, nil
}

// Run will execute the script
func (d *LuaEngine) Run(pkt *Packet) error {
/* preload */
d.pkt = &pkt
for _, v := range d.functions {
err := d.LuaEngine.DoString(v)
if err != nil {
return err
}
}
return nil
}
Loading

0 comments on commit e942481

Please sign in to comment.