first commit
This commit is contained in:
209
openldap-log-parser.go
Normal file
209
openldap-log-parser.go
Normal file
@ -0,0 +1,209 @@
|
||||
package openldaplog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
SyslogPri = `(?:<\d{1,3}>)?`
|
||||
TimeFormat = "Jan 2 15:04:05"
|
||||
TimeFormatISO8601 = "2006-01-02T15:04:05.999999-07:00"
|
||||
// group[1]
|
||||
TimeRE = `([A-Za-z]{3}\s*[0-9]{1,2} [0-9]{2}:[0-9]{2}:[0-9]{2}|^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:[+-][0-2]\d:[0-5]\d|Z))`
|
||||
IPv4RE = `(?:\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}`
|
||||
// FIXME: Not very strict
|
||||
IPv6RE = `(?:(?:[0-9a-fA-F]{1,4}\:){7})[0-9a-fA-F]{1,4}`
|
||||
HostRE = `([0-9A-Za-z\-\_\.]*)`
|
||||
ProcessRE = `(slapd\[[0-9]{1,5}\])`
|
||||
// group[4]
|
||||
ConnIdRE = `conn=([0-9]{4,10})`
|
||||
ConnFdRE = `(?:fd=([0-9]{1,10}))?`
|
||||
OperationIdRE = `(?:op=([0-9]{1,10}))?`
|
||||
AcceptRE = `(?:ACCEPT from IP=(` + IPv4RE + `)\:([0-9]{1,5}) \(IP=(` + IPv4RE + `)\:([0-9]{1,5})\))?`
|
||||
// group[11]
|
||||
STARTTLSRE = `(STARTTLS$)?`
|
||||
// group[12], group[13]
|
||||
BindMethodRE = `(?:BIND dn="(.*)" method=([0-9]{1,3}))?`
|
||||
BindMechRE = `(?:BIND dn=".*" mech=([a-zA-Z]*) (?:bind_ssf=([0-9]{1,3}) )?ssf=([0-9]{1,3}))?`
|
||||
// group[17], group[18], group[19], group[20], group[21], group[22], group[23]
|
||||
ResultRE = `(?:(RESULT) (?:tag=([0-9]{1,3})|oid=([0-9\.]*)) err=([0-9]{1,3}) (?:qtime=([0-9\.]{1,10}) )?(?:etime=([0-9\.]{1,10}) )?text=(.*))?`
|
||||
SearchBaseRE = `(?:SRCH base="(.*)" scope=([0-2]) deref=([0-3]) filter="(.*)")?`
|
||||
// group[28]
|
||||
SearchAttrRE = `(?:SRCH attr=(.*))?`
|
||||
// group[29], group[30], group[31], group[32], group[33], group[34], group[35]
|
||||
SearchResultRE = `(?:(SEARCH RESULT) tag=([0-9]{1,3}) err=([0-9]{1,3}) (?:qtime=([0-9\.]{1,10}) )?(?:etime=([0-9\.]{1,10}) )?nentries=([0-9]{1,9}) text=(.*))?`
|
||||
ModDnRE = `(?:MOD dn="(.*)")?`
|
||||
ModAttrRE = `(?:MOD attr=(.*))?`
|
||||
// group[38]
|
||||
PassModRE = `(?:PASSMOD id="(.*)" new)?`
|
||||
UnbindRE = `(UNBIND)?`
|
||||
// group[40]
|
||||
ConnClosedRE = `(closed)?(?: \(connection lost\))?`
|
||||
|
||||
LogLineRE = SyslogPri + TimeRE + ` ` + HostRE + ` ` + ProcessRE + ` ` + ConnIdRE + ` ` + ConnFdRE + OperationIdRE + ` ` +
|
||||
AcceptRE + STARTTLSRE + BindMethodRE + BindMechRE + ResultRE + SearchBaseRE + SearchAttrRE + SearchResultRE + ModDnRE + ModAttrRE +
|
||||
PassModRE + UnbindRE + ConnClosedRE
|
||||
)
|
||||
|
||||
type (
|
||||
OpenldapLog struct {
|
||||
LogFormat LogFormat
|
||||
Regexp *regexp.Regexp
|
||||
}
|
||||
|
||||
LogFormat struct {
|
||||
Time *time.Time `json:"time"`
|
||||
Hostname string `json:"hostname"`
|
||||
Process string `json:"process"`
|
||||
ClientIp string `json:"client_ip"`
|
||||
ClientPort int `json:"client_port"`
|
||||
ServerIp string `json:"server_ip"`
|
||||
ServerPort int `json:"server_port"`
|
||||
BindDN string `json:"bind_dn"`
|
||||
ConnId int `json:"conn_id"`
|
||||
ConnFd int `json:"conn_fd"`
|
||||
OpId int `json:"op_id"`
|
||||
OpType string `json:"op_type"`
|
||||
BindMethod string `json:"bind_method"`
|
||||
BindMech string `json:"bind_mech"`
|
||||
BindSSF string `json:"bind_ssf"`
|
||||
SSF string `json:"ssf"`
|
||||
ModDN string `json:"mod_dn"`
|
||||
ModAttr string `json:"mod_attr"`
|
||||
PassModDN string `json:"passmod_dn"`
|
||||
Result bool
|
||||
ResTag string `json:"result_tag"`
|
||||
ResOid string `json:"result_oid"`
|
||||
ResErr int `json:"result_err"`
|
||||
ResQTime string `json:"result_qtime"`
|
||||
ResETime string `json:"result_etime"`
|
||||
ResText string `json:"result_text"`
|
||||
SearchResult bool
|
||||
SearchBase string `json:"search_base"`
|
||||
SearchScope string `json:"search_scope"`
|
||||
SearchDeref string `json:"search_deref"`
|
||||
SearchFilter string `json:"search_filter"`
|
||||
SearchAttr string `json:"search_attr"`
|
||||
SearchResTag string `json:"search_res_tag"`
|
||||
SearchResErr int `json:"search_res_err"`
|
||||
SearchResQTime string `json:"search_res_qtime"`
|
||||
SearchResETime string `json:"search_res_etime"`
|
||||
SearchResNEntries int `json:"search_res_nentries"`
|
||||
SearchResText string `json:"search_res_text"`
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
gDebug bool
|
||||
)
|
||||
|
||||
func NewOpenldapLog(debug bool) *OpenldapLog {
|
||||
if debug {
|
||||
gDebug = true
|
||||
fmt.Printf("DEBUG: Regexp will display on next line\n")
|
||||
fmt.Printf("%s\n", LogLineRE)
|
||||
}
|
||||
return &OpenldapLog{
|
||||
Regexp: regexp.MustCompile(LogLineRE),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OpenldapLog) Parse(text []byte) (LogFormat, error) {
|
||||
re := o.Regexp.Copy()
|
||||
group := re.FindSubmatch(text)
|
||||
if len(group) == 0 {
|
||||
err := errors.New("Error: Line do not match regex")
|
||||
return LogFormat{}, err
|
||||
}
|
||||
var t time.Time
|
||||
t, err := time.ParseInLocation(TimeFormat, string(group[1]), time.Local)
|
||||
if err != nil {
|
||||
t, err = time.ParseInLocation(TimeFormatISO8601, string(group[1]), time.Local)
|
||||
if err != nil {
|
||||
return LogFormat{}, err
|
||||
}
|
||||
}
|
||||
|
||||
cid,_ := strconv.Atoi(string(group[4]))
|
||||
cfd,_ := strconv.Atoi(string(group[5]))
|
||||
opid,_ := strconv.Atoi(string(group[6]))
|
||||
cport,_ := strconv.Atoi(string(group[8]))
|
||||
sport,_ := strconv.Atoi(string(group[10]))
|
||||
result := false
|
||||
if string(group[17]) == "RESULT" {
|
||||
result = true
|
||||
}
|
||||
rerr,_ := strconv.Atoi(string(group[20]))
|
||||
sresult := false
|
||||
if string(group[29]) == "SEARCH RESULT" {
|
||||
sresult = true
|
||||
}
|
||||
serr,_ := strconv.Atoi(string(group[31]))
|
||||
srentries, _ := strconv.Atoi(string(group[34]))
|
||||
|
||||
logFormat := LogFormat{
|
||||
Time: &t,
|
||||
Hostname: string(group[2]),
|
||||
Process: string(group[3]),
|
||||
ConnId: cid,
|
||||
ConnFd: cfd,
|
||||
OpId: opid,
|
||||
ClientIp: string(group[7]),
|
||||
ClientPort: cport,
|
||||
ServerIp: string(group[9]),
|
||||
ServerPort: sport,
|
||||
// "STARTTLS"
|
||||
BindDN: string(group[12]),
|
||||
BindMethod: string(group[13]),
|
||||
BindMech: string(group[14]),
|
||||
BindSSF: string(group[15]),
|
||||
SSF: string(group[16]),
|
||||
Result: result,
|
||||
ResTag: string(group[18]),
|
||||
ResOid: string(group[19]),
|
||||
ResErr: rerr,
|
||||
ResQTime: string(group[21]),
|
||||
ResETime: string(group[22]),
|
||||
ResText: string(group[23]),
|
||||
SearchBase: string(group[24]),
|
||||
SearchScope: string(group[25]),
|
||||
SearchDeref: string(group[26]),
|
||||
SearchFilter: string(group[27]),
|
||||
SearchAttr: string(group[28]),
|
||||
SearchResult: sresult,
|
||||
SearchResTag: string(group[30]),
|
||||
SearchResErr: serr,
|
||||
SearchResQTime: string(group[32]),
|
||||
SearchResETime: string(group[33]),
|
||||
SearchResNEntries: srentries,
|
||||
SearchResText: string(group[35]),
|
||||
ModDN: string(group[36]),
|
||||
ModAttr: string(group[37]),
|
||||
PassModDN: string(group[38]),
|
||||
}
|
||||
|
||||
// Now handle Operation Type
|
||||
if len(group[11]) > 0 || len(group[13]) > 0 || len(group[14]) > 0 || len(group[15]) > 0 {
|
||||
logFormat.OpType = "bind"
|
||||
} else if len(group[11]) > 0 {
|
||||
logFormat.OpType = "starttls"
|
||||
} else if len(group[24]) > 0 {
|
||||
logFormat.OpType = "search"
|
||||
} else if len(group[7]) > 0 {
|
||||
logFormat.OpType = "accept"
|
||||
} else if len(group[36]) > 0 || len(group[37]) > 0 {
|
||||
logFormat.OpType = "mod"
|
||||
} else if len(group[38]) > 0 {
|
||||
logFormat.OpType = "passmod"
|
||||
} else if len(group[39]) > 0 {
|
||||
logFormat.OpType = "unbind"
|
||||
} else if len(group[40]) > 0 {
|
||||
logFormat.OpType = "close"
|
||||
}
|
||||
|
||||
return logFormat, nil
|
||||
}
|
||||
Reference in New Issue
Block a user