Восстановление репозитория
This commit is contained in:
commit
4113bcbd7d
22
Dockerfile
Normal file
22
Dockerfile
Normal file
|
@ -0,0 +1,22 @@
|
|||
FROM golang:alpine3.16 AS build
|
||||
RUN apk --no-cache add gcc g++ make git
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
RUN go get net/netip
|
||||
RUN go get ./...
|
||||
|
||||
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/zimbra-alarm ./zimbra-alarm.go
|
||||
FROM alpine:3.16
|
||||
RUN apk add tzdata
|
||||
WORKDIR /usr/bin
|
||||
COPY --from=build /go/src/app/bin /go/bin
|
||||
|
||||
COPY entrypoint.sh .
|
||||
|
||||
# COPY cronjobs /etc/crontabs/root
|
||||
|
||||
# start crond with log level 8 in foreground, output to stderr
|
||||
# CMD ["crond", "-f", "-d", "8"]
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]
|
||||
|
77
README.md
Normal file
77
README.md
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Описание
|
||||
|
||||
Получение и обработка данных о пользовательских сессиях (авторизация) при соединении с почтовой системой. И блокирование нежелательных адресов.
|
||||
|
||||
Для работы требуется ElasticSearch, PostgreSQL, докер (опционально).
|
||||
|
||||
## zimbra-alarm
|
||||
|
||||
Программа zimbra-alarm получает из elasticsearch, список пользовательских сессий за заданный промежуток времени (4 минуты). Для определения из каких индексов производить выборку данных, первоначально загружается список всех индексов из эластика (без временной метки), далее выбираются имена индексов соответствующие заданным шаблонам (префиксам), по умолчанию это maillog-mailbox. И для каждого типа индексов (например maillog_mailbox1_filebeat*, maillog_mailbox2_filebeat* и т.п.) запускается параллельный процесс поиска и выгрузки данных. Данные обрабатываются и складываются в таблицу 'mail_sessions' СУБД Postgresql, для каждого почтового аккаунта соединения с одного ip адреса суммируются в одну запись с зафиксированной меткой времени.
|
||||
Почтовые аккаунты сохраняются в таблице mail_accounts.
|
||||
|
||||
После этого запускается процесс анализа данных о сессиях и генерации сообщений о "тревогах" (таблица 'alarm'):
|
||||
|
||||
1. Если количество сессий с одного адреса в один аккаунт превышает заданное число (50), будет создано сообщение об аномалии с типом "2" ("Количество сессий больше заданного")
|
||||
2. Если код geoip ip-адреса не равен "RU" - будет создана запись c ip-адресом и типом "1" ("Неразрешенный код страны")
|
||||
3. Если зафиксированы соединения в один почтовый аккаунт с разных адресов, то будет сгенерировано сообщение с типом "3" ("Вход в аккаунт более чем с одного IP")
|
||||
4. Если с одного ip-адреса, для которого есть запись с типом 1 (неразрешенный код страны), были попытки входа в несколько учетных записей, то будет добавлена запись с типом "4" ("Вход более чем в один аккаунт")
|
||||
|
||||
Если для одного почтового аккаунта или одного ip-адреса будет сгенерировано сообщение о тревоги с одним и тмеже типом, то существующая запись о тревоге обновиться с последней меткой времени.
|
||||
|
||||
Программу можно запускать как в консоли так и в docker-контейнере.
|
||||
|
||||
## alarmaction
|
||||
|
||||
Программа "alarmaction" предназначена для выполнения действий по "тревогам". На данный момент доступно блокирование ip адресов через "iptables". Устанавливается на целевых узлах (в нашем случае MTA сервера mail и mail2). Запуск производится через службу "crond".
|
||||
|
||||
При запуске программы, происходит чтение таблицы "alarm" из БД. Выбираются все записи с типом 4 (alarm_type=4) и пустым полем "<hostname>_action_timestamp, где "<hostname>" - укороченное имя узла (в нашем случае "mail_action_timestamp" и "mail2_action_timestamp").
|
||||
|
||||
Выбранные ip-адреса будут блокированы через iptables на каждом из узлов и после успешного выполнения блокровки в соответствующая запись в таблице будет изменена (добавлена временная метка в нужное поле, см. выше).
|
||||
|
||||
Все адреса в iptables заносятся в цепочку "auto_blocked" которая будет создана при первом запуске alarmaction.
|
||||
|
||||
Для исключения блокирования определенных адресов или подсетей в таблицу filter необходимо добавить соответствующую запись (адрес и маску):
|
||||
|
||||
```
|
||||
INSERT INTO filter(remote_ip, description) values('192.168.0.0/16', 'Локальная сеть')
|
||||
```
|
||||
|
||||
# Запуск
|
||||
|
||||
zimbra-alarm можно запускать как по времени так и в докер-контейнере. alarmaction - запускается по времени.
|
||||
|
||||
Для работы обоих программ нужно установить переменные окружения:
|
||||
|
||||
zimbra-alarm:
|
||||
|
||||
- ELASTICSEARCH_URL=https://${ELASTIC_USER}:${ELASTIC_PASSWORD}@${ELASTIC_HOST}:9200 - строка соедения с ElasticSearch
|
||||
- PGHOST=dbserver - сервер СУБД (PostgreSQL)
|
||||
- PGDATABASE=mail_alarm - имя базы данных
|
||||
- PGUSER=mail_alarm - пользователь БД
|
||||
- PGPASSWORD={PGPASSWORD} - пароль пользователя
|
||||
- REQUEST_TIME_RANGE=4 - время за которое запрашиваются данные в минутах (по умолчанию 4м)
|
||||
- REQUEST_ROWS=10000 - количество строк возвращаемое запросом (по умолчанию 10000)
|
||||
|
||||
команда запуска:
|
||||
|
||||
см. entrypoint.sh
|
||||
|
||||
```
|
||||
zimbra-alarm --indexname "maillog_mailbox" -timerange "${REQUEST_TIME_RANGE}m" -operation es-request-data -pg-insert -request-rows ${REQUEST_ROWS}
|
||||
```
|
||||
|
||||
alarmaction:
|
||||
|
||||
- PGHOST=dbserver
|
||||
- PGUSER=pguser
|
||||
- PGDATABASE=maildb
|
||||
- PGPASSWORD=pgpassword
|
||||
- ALARM_LOG_FILE=/var/log/alarmaction.log
|
||||
|
||||
команда запуска:
|
||||
|
||||
см. alarmaction.cron
|
||||
|
||||
```
|
||||
alarmaction
|
||||
```
|
320
alarmaction-v1.go
Normal file
320
alarmaction-v1.go
Normal file
|
@ -0,0 +1,320 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Получение и обработка данных о пользовательских сессиях (авторизация)
|
||||
// при соединении с почтовой системой. И блокирование нежелательных адресов.
|
||||
// ---------------------------------------------------------------------------
|
||||
// Версия 1 (iptables)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
"net/netip"
|
||||
"time"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/coreos/go-iptables/iptables"
|
||||
"github.com/jackc/pgx/v5"
|
||||
// "github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Alarm struct {
|
||||
Id int32
|
||||
Mail_account_id int32
|
||||
Remote_ip netip.Prefix
|
||||
Country_code string
|
||||
Last_time string
|
||||
Last_check_timestamp time.Time
|
||||
Action_timestamp time.Time
|
||||
Alarm_type int
|
||||
Alarm_action bool
|
||||
Hostname string
|
||||
}
|
||||
|
||||
// PIDFile stored the process id
|
||||
type PIDFile struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var PID_file_path = "/var/run/alarmaction.pid"
|
||||
|
||||
// Remove the pid file
|
||||
// func (file PIDFile) PIDRemove() error {
|
||||
// return os.Remove(file.path)
|
||||
// }
|
||||
|
||||
func ProcessExit(exit_code int) {
|
||||
if exit_code == 0 {
|
||||
os.Remove(PID_file_path)
|
||||
}
|
||||
os.Exit(exit_code)
|
||||
}
|
||||
|
||||
// Выборка записей по конкретному IP
|
||||
// запросы разные в зависимости от типа тревоги
|
||||
func PgSelectAlarmRemoteIP(alarm Alarm) pgx.Rows {
|
||||
var query string
|
||||
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
// fmt.Println(*conn)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
switch alarm.Alarm_type {
|
||||
case 4:
|
||||
query = fmt.Sprintf("select id, remote_ip from alarm where alarm_type = %v and \"%v_action_timestamp\" is NULL", alarm.Alarm_type, alarm.Hostname)
|
||||
}
|
||||
log.Println(query)
|
||||
rows, err_select := conn.Query(context.Background(), query)
|
||||
|
||||
if err_select != nil {
|
||||
log.Println("Query alarms failed PgSelectAlarmRemoteIP:", err_select)
|
||||
ProcessExit(1)
|
||||
}
|
||||
if len(rows.FieldDescriptions()) == 0 {
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
// log.Println("Selected an:",len(rows.FieldDescriptions()), "records")
|
||||
|
||||
defer conn.Close(context.Background())
|
||||
return rows
|
||||
}
|
||||
// Проверка на соответствие адреса записи в filter
|
||||
func PgSelectFilterIP(ip netip.Prefix) int32 {
|
||||
var query string
|
||||
var id int32
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
// fmt.Println(*conn)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
// проверяем адрес на совпадение с фильтром (для исключения)
|
||||
// select * from filter where remote_ip >>= inet '209.85.161.20/32'
|
||||
query = fmt.Sprintf("select id from filter where remote_ip >>= inet '%v'", ip)
|
||||
log.Println(query)
|
||||
err_select := conn.QueryRow(context.Background(), query).Scan(&id)
|
||||
|
||||
if err_select != nil {
|
||||
log.Println("Select filter for remote ip", ip, "error:", err)
|
||||
if err_select.Error() == "no rows in result set" {
|
||||
id = 0
|
||||
} else {
|
||||
ProcessExit(1)
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
func PgUpdateAlarm(conn *pgx.Conn, alarm Alarm, id int32) int32 {
|
||||
log.Println("Update alarm data", alarm)
|
||||
t := time.Now().Format("2006-01-02 15:04:05")
|
||||
query := fmt.Sprintf("update alarm set \"%v_action_timestamp\"='%v' where id=%v returning id", alarm.Hostname, t, id)
|
||||
log.Println("Update alarm query:", query)
|
||||
err := conn.QueryRow(context.Background(), query).Scan(&id)
|
||||
if err != nil {
|
||||
log.Printf("Update alarm data failed: %v\n", err)
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
func IpTablesCreateChain (sChain string) bool {
|
||||
ipt, err := iptables.New()
|
||||
if err != nil {
|
||||
log.Printf("Failed to new up an IPtables intance. ERROR: %v", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
var chain_exists bool
|
||||
chain_exists, err = ipt.ChainExists("filter", sChain)
|
||||
if err != nil {
|
||||
log.Printf("Failed to checking chain (%v). ERROR: %v", sChain , err)
|
||||
return false
|
||||
}
|
||||
if chain_exists {
|
||||
return true
|
||||
} else {
|
||||
err = ipt.NewChain("filter", sChain)
|
||||
if err != nil {
|
||||
log.Printf("Failed to creating chain (%v). ERROR: %v", sChain , err)
|
||||
return false
|
||||
}
|
||||
err = ipt.AppendUnique("filter", "INPUT", "-j", sChain)
|
||||
if err != nil {
|
||||
log.Printf("Failed to append chain. ERROR: %v", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func BlockIP(ip netip.Prefix, sChain string, dChain string) bool {
|
||||
// Some default chain names
|
||||
|
||||
// Get a new iptables interface
|
||||
ipt, err := iptables.New()
|
||||
if err != nil {
|
||||
log.Printf("Failed to new up an IPtables intance. ERROR: %v", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
// Build out the ipstring(add /32 to the end)
|
||||
ipstr := fmt.Sprintf("%s", ip)
|
||||
res, _ := ipt.Exists("filter", sChain, "-s", ipstr, "-j", dChain)
|
||||
if !res {
|
||||
// Use the appendUnique method to put this in iptables, but only once
|
||||
err = ipt.AppendUnique("filter", sChain, "-s", ipstr, "-j", dChain)
|
||||
if err != nil {
|
||||
log.Printf("Failed to ban an ip(%v). ERROR: %v", ipstr , err)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
log.Printf("Failed to ban an ip(%v). ERROR: Address already banned", ipstr)
|
||||
}
|
||||
|
||||
// Since we made it here, we won
|
||||
return true
|
||||
}
|
||||
|
||||
// just suit for linux
|
||||
func processExists(pid string) bool {
|
||||
if _, err := os.Stat(filepath.Join("/proc", pid)); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkPIDFILEAlreadyExists(path string) error {
|
||||
if pidByte, err := ioutil.ReadFile(path); err == nil {
|
||||
pid := strings.TrimSpace(string(pidByte))
|
||||
if processExists(pid) {
|
||||
return fmt.Errorf("ensure the process:%s is not running pid file:%s", pid, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPIDFile create the pid file
|
||||
// path specified under production pidfile, file content pid
|
||||
func NewPIDFile(path string) (*PIDFile, error) {
|
||||
if err := checkPIDFILEAlreadyExists(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PIDFile{path: path}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Создадим и откроем на запись файл для логов
|
||||
var alarm_log_file string
|
||||
if os.Getenv("ALARM_LOG_FILE") == "" {
|
||||
alarm_log_file = "alarmaction.log"
|
||||
} else {
|
||||
alarm_log_file = os.Getenv("ALARM_LOG_FILE")
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(alarm_log_file, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
log.SetOutput(f)
|
||||
|
||||
// Создание PID файла
|
||||
_, err = NewPIDFile(PID_file_path)
|
||||
if err != nil {
|
||||
log.Println("error to create the pid file failed:", err.Error())
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
// Проверка переменных окружения
|
||||
if os.Getenv("PGHOST") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGHOST` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
if os.Getenv("PGUSER") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGUSER` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
if os.Getenv("PGPASSWORD") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGPASSWORD` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
if os.Getenv("PGDATABASE") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGDATABASE` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
// if os.Getenv("HOSTNAME") == "" {
|
||||
// fmt.Println("Send error: make sure environment variables `HOSTNAME` was set")
|
||||
// ProcessExit(1)
|
||||
// }
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
// fmt.Println(*conn)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
sChain := "auto_blocked"
|
||||
dChain := "DROP"
|
||||
|
||||
if !IpTablesCreateChain(sChain) {
|
||||
log.Println("Iptables chain", sChain, "does not exists")
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
var alarm Alarm
|
||||
|
||||
alarm.Hostname = strings.Split(hostname, ".")[0]
|
||||
alarm.Action_timestamp = time.Unix(time.Now().Unix(), 0)
|
||||
alarm.Alarm_type = 4
|
||||
|
||||
res := PgSelectAlarmRemoteIP(alarm)
|
||||
var id int32
|
||||
var ip netip.Prefix
|
||||
var filter_id int32
|
||||
for res.Next() {
|
||||
values, _ := res.Values()
|
||||
id = values[0].(int32)
|
||||
ip = values[1].(netip.Prefix)
|
||||
filter_id = PgSelectFilterIP(ip)
|
||||
log.Println(filter_id)
|
||||
if filter_id > 0 {
|
||||
log.Println("The ip address", ip, "is conained in filter table")
|
||||
log.Println(PgUpdateAlarm(conn, alarm, id))
|
||||
// continue
|
||||
} else {
|
||||
fmt.Println(id, ip)
|
||||
if BlockIP(ip, sChain, dChain) {
|
||||
log.Println("The ip address", ip, "was blocked")
|
||||
alarm.Alarm_action = true
|
||||
log.Println(PgUpdateAlarm(conn, alarm, id))
|
||||
}
|
||||
}
|
||||
}
|
||||
ProcessExit(0)
|
||||
}
|
9
alarmaction.cron
Normal file
9
alarmaction.cron
Normal file
|
@ -0,0 +1,9 @@
|
|||
PGHOST=build1.corp.samsonopt.ru
|
||||
PGUSER=pguser
|
||||
PGDATABASE=maildb
|
||||
PGPASSWORD=pgpassword
|
||||
PATH=$PATH:/usr/sbin
|
||||
ALARM_LOG_FILE=/var/log/alarmaction.log
|
||||
|
||||
*/1 * * * * root /usr/local/bin/alarmaction >> /var/log/alarmaction.log 2>&1
|
||||
|
371
alarmaction.go
Normal file
371
alarmaction.go
Normal file
|
@ -0,0 +1,371 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Получение и обработка данных о пользовательских сессиях (авторизация)
|
||||
// при соединении с почтовой системой. И блокирование нежелательных адресов.
|
||||
// ---------------------------------------------------------------------------
|
||||
// Версия 2 (ipset)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
"net/netip"
|
||||
"time"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
// "github.com/coreos/go-iptables/iptables"
|
||||
"github.com/gonetx/ipset"
|
||||
"github.com/jackc/pgx/v5"
|
||||
// "github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
// проверяем наличие ipset системе
|
||||
func CheckIPSet() {
|
||||
if err := ipset.Check(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type Alarm struct {
|
||||
Id int32
|
||||
Mail_account_id int32
|
||||
Remote_ip netip.Prefix
|
||||
Country_code string
|
||||
Last_time string
|
||||
Last_check_timestamp time.Time
|
||||
Action_timestamp time.Time
|
||||
Alarm_type int
|
||||
Alarm_action bool
|
||||
Hostname string
|
||||
}
|
||||
|
||||
// PIDFile stored the process id
|
||||
type PIDFile struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var PID_file_path = "/var/run/alarmaction.pid"
|
||||
|
||||
// Remove the pid file
|
||||
// func (file PIDFile) PIDRemove() error {
|
||||
// return os.Remove(file.path)
|
||||
// }
|
||||
|
||||
func ProcessExit(exit_code int) {
|
||||
if exit_code == 0 {
|
||||
os.Remove(PID_file_path)
|
||||
}
|
||||
os.Exit(exit_code)
|
||||
}
|
||||
|
||||
// Выборка записей по конкретному IP
|
||||
// запросы разные в зависимости от типа тревоги
|
||||
func PgSelectAlarmRemoteIP(alarm Alarm) pgx.Rows {
|
||||
var query string
|
||||
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
// fmt.Println(*conn)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
switch alarm.Alarm_type {
|
||||
case 4:
|
||||
query = fmt.Sprintf("select id, remote_ip from alarm where alarm_type = %v and \"%v_action_timestamp\" is NULL", alarm.Alarm_type, alarm.Hostname)
|
||||
}
|
||||
log.Println(query)
|
||||
rows, err_select := conn.Query(context.Background(), query)
|
||||
|
||||
if err_select != nil {
|
||||
log.Println("Query alarms failed PgSelectAlarmRemoteIP:", err_select)
|
||||
ProcessExit(1)
|
||||
}
|
||||
if len(rows.FieldDescriptions()) == 0 {
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
// log.Println("Selected an:",len(rows.FieldDescriptions()), "records")
|
||||
|
||||
defer conn.Close(context.Background())
|
||||
return rows
|
||||
}
|
||||
// Проверка на соответствие адреса записи в filter
|
||||
func PgSelectFilterIP(ip netip.Prefix) int32 {
|
||||
var query string
|
||||
var id int32
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
// fmt.Println(*conn)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
// проверяем адрес на совпадение с фильтром (для исключения)
|
||||
// select * from filter where remote_ip >>= inet '209.85.161.20/32'
|
||||
query = fmt.Sprintf("select id from filter where remote_ip >>= inet '%v'", ip)
|
||||
log.Println(query)
|
||||
err_select := conn.QueryRow(context.Background(), query).Scan(&id)
|
||||
|
||||
if err_select != nil {
|
||||
log.Println("Select filter for remote ip", ip, "error:", err)
|
||||
if err_select.Error() == "no rows in result set" {
|
||||
id = 0
|
||||
} else {
|
||||
ProcessExit(1)
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
func PgUpdateAlarm(conn *pgx.Conn, alarm Alarm, id int32) int32 {
|
||||
log.Println("Update alarm data", alarm)
|
||||
t := time.Now().Format("2006-01-02 15:04:05")
|
||||
query := fmt.Sprintf("update alarm set \"%v_action_timestamp\"='%v' where id=%v returning id", alarm.Hostname, t, id)
|
||||
log.Println("Update alarm query:", query)
|
||||
err := conn.QueryRow(context.Background(), query).Scan(&id)
|
||||
if err != nil {
|
||||
log.Printf("Update alarm data failed: %v\n", err)
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// func IpTablesCreateChain (sChain string) bool {
|
||||
// ipt, err := iptables.New()
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to new up an IPtables intance. ERROR: %v", err)
|
||||
// ProcessExit(1)
|
||||
// }
|
||||
// var chain_exists bool
|
||||
// chain_exists, err = ipt.ChainExists("filter", sChain)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to checking chain (%v). ERROR: %v", sChain , err)
|
||||
// return false
|
||||
// }
|
||||
// if chain_exists {
|
||||
// return true
|
||||
// } else {
|
||||
// err = ipt.NewChain("filter", sChain)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to creating chain (%v). ERROR: %v", sChain , err)
|
||||
// return false
|
||||
// }
|
||||
// err = ipt.AppendUnique("filter", "INPUT", "-j", sChain)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to append chain. ERROR: %v", err)
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true
|
||||
//
|
||||
// }
|
||||
|
||||
// func BlockIP(ip netip.Prefix, sChain string, dChain string) bool {
|
||||
// // Some default chain names
|
||||
//
|
||||
// // Get a new iptables interface
|
||||
// ipt, err := iptables.New()
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to new up an IPtables intance. ERROR: %v", err)
|
||||
// ProcessExit(1)
|
||||
// }
|
||||
// // Build out the ipstring(add /32 to the end)
|
||||
// ipstr := fmt.Sprintf("%s", ip)
|
||||
// res, _ := ipt.Exists("filter", sChain, "-s", ipstr, "-j", dChain)
|
||||
// if !res {
|
||||
// // Use the appendUnique method to put this in iptables, but only once
|
||||
// err = ipt.AppendUnique("filter", sChain, "-s", ipstr, "-j", dChain)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to ban an ip(%v). ERROR: %v", ipstr , err)
|
||||
// return false
|
||||
// }
|
||||
// } else {
|
||||
// log.Printf("Failed to ban an ip(%v). ERROR: Address already banned", ipstr)
|
||||
// }
|
||||
//
|
||||
// // Since we made it here, we won
|
||||
// return true
|
||||
// }
|
||||
func BlockIP(ip netip.Prefix, sChain string, dChain string) bool {
|
||||
// create test set even it's exist
|
||||
// set, err := ipset.New("auto_blocked", ipset.HashIp, ipset.Exist(true), ipset.Timeout(time.Hour))
|
||||
ip_address := ip.String()
|
||||
set, err := ipset.New("auto-blocked-ipset", ipset.HashIp, ipset.Exist(true))
|
||||
// output: test
|
||||
if err != nil {
|
||||
log.Printf("Failed to create new ipset rule. ERROR: %v", err)
|
||||
// return false
|
||||
} else {
|
||||
log.Printf("New ipset rule %v was created", set.Name())
|
||||
}
|
||||
|
||||
// _ = set.Flush()
|
||||
|
||||
// _ = set.Add("1.1.1.1", ipset.Timeout(time.Hour))
|
||||
err = set.Add(ip_address)
|
||||
if err != nil {
|
||||
log.Printf("Failed to added new %v to set. ERROR: %v", ip_address, err)
|
||||
return false
|
||||
}
|
||||
|
||||
ok, err := set.Test(ip_address)
|
||||
// output: true
|
||||
log.Println(ok)
|
||||
if err != nil {
|
||||
log.Printf("Failed to added new %v to set. ERROR: %v", ip_address, err)
|
||||
return false
|
||||
}
|
||||
|
||||
// ok, _ = set.Test("1.1.1.2")
|
||||
// output: false
|
||||
// log.Println(ok)
|
||||
|
||||
// info, _ := set.List()
|
||||
// output: &{test hash:ip 4 family inet hashsize 1024 maxelem 65536 timeout 3600 216 0 [1.1.1.1 timeout 3599]}
|
||||
// log.Println(info)
|
||||
|
||||
// _ = set.Del("1.1.1.1")
|
||||
|
||||
// _ = set.Destroy()
|
||||
return true
|
||||
}
|
||||
|
||||
// just suit for linux
|
||||
func processExists(pid string) bool {
|
||||
if _, err := os.Stat(filepath.Join("/proc", pid)); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkPIDFILEAlreadyExists(path string) error {
|
||||
if pidByte, err := ioutil.ReadFile(path); err == nil {
|
||||
pid := strings.TrimSpace(string(pidByte))
|
||||
if processExists(pid) {
|
||||
return fmt.Errorf("ensure the process:%s is not running pid file:%s", pid, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPIDFile create the pid file
|
||||
// path specified under production pidfile, file content pid
|
||||
func NewPIDFile(path string) (*PIDFile, error) {
|
||||
if err := checkPIDFILEAlreadyExists(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PIDFile{path: path}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
CheckIPSet()
|
||||
// Создадим и откроем на запись файл для логов
|
||||
var alarm_log_file string
|
||||
if os.Getenv("ALARM_LOG_FILE") == "" {
|
||||
alarm_log_file = "alarmaction.log"
|
||||
} else {
|
||||
alarm_log_file = os.Getenv("ALARM_LOG_FILE")
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(alarm_log_file, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
log.SetOutput(f)
|
||||
|
||||
// Создание PID файла
|
||||
_, err = NewPIDFile(PID_file_path)
|
||||
if err != nil {
|
||||
log.Println("error to create the pid file failed:", err.Error())
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
// Проверка переменных окружения
|
||||
if os.Getenv("PGHOST") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGHOST` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
if os.Getenv("PGUSER") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGUSER` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
if os.Getenv("PGPASSWORD") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGPASSWORD` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
if os.Getenv("PGDATABASE") == "" {
|
||||
fmt.Println("Send error: make sure environment variables `PGDATABASE` was set")
|
||||
ProcessExit(1)
|
||||
}
|
||||
// if os.Getenv("HOSTNAME") == "" {
|
||||
// fmt.Println("Send error: make sure environment variables `HOSTNAME` was set")
|
||||
// ProcessExit(1)
|
||||
// }
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
// fmt.Println(*conn)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
ProcessExit(1)
|
||||
}
|
||||
|
||||
sChain := "auto_blocked"
|
||||
dChain := "DROP"
|
||||
|
||||
// if !IpTablesCreateChain(sChain) {
|
||||
// log.Println("Iptables chain", sChain, "does not exists")
|
||||
// ProcessExit(1)
|
||||
// }
|
||||
|
||||
var alarm Alarm
|
||||
|
||||
alarm.Hostname = strings.Split(hostname, ".")[0]
|
||||
alarm.Action_timestamp = time.Unix(time.Now().Unix(), 0)
|
||||
alarm.Alarm_type = 4
|
||||
|
||||
res := PgSelectAlarmRemoteIP(alarm)
|
||||
var id int32
|
||||
var ip netip.Prefix
|
||||
var filter_id int32
|
||||
for res.Next() {
|
||||
values, _ := res.Values()
|
||||
id = values[0].(int32)
|
||||
ip = values[1].(netip.Prefix)
|
||||
filter_id = PgSelectFilterIP(ip)
|
||||
log.Println(filter_id)
|
||||
if filter_id > 0 {
|
||||
log.Println("The ip address", ip, "is conained in filter table")
|
||||
log.Println(PgUpdateAlarm(conn, alarm, id))
|
||||
// continue
|
||||
} else {
|
||||
fmt.Println(id, ip)
|
||||
if BlockIP(ip, sChain, dChain) {
|
||||
log.Println("The ip address", ip, "was blocked")
|
||||
alarm.Alarm_action = true
|
||||
log.Println(PgUpdateAlarm(conn, alarm, id))
|
||||
}
|
||||
}
|
||||
}
|
||||
ProcessExit(0)
|
||||
}
|
148
database.sql.j2
Normal file
148
database.sql.j2
Normal file
|
@ -0,0 +1,148 @@
|
|||
-- DROP DATABASE {{ db_name }};
|
||||
|
||||
-- CREATE DATABASE {{ db_name }}
|
||||
-- WITH
|
||||
-- OWNER = {{ db_user }}
|
||||
-- ENCODING = 'UTF8'
|
||||
-- LC_COLLATE = 'en_US.utf8'
|
||||
-- LC_CTYPE = 'en_US.utf8'
|
||||
-- TABLESPACE = pg_default
|
||||
-- CONNECTION LIMIT = -1;
|
||||
|
||||
CREATE SEQUENCE public.alarm_id_seq
|
||||
INCREMENT 1
|
||||
START 1
|
||||
MINVALUE 1
|
||||
MAXVALUE 2147483647
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.alarm_id_seq
|
||||
OWNER TO {{ db_user }};
|
||||
|
||||
|
||||
CREATE SEQUENCE public.mail_accounts_id_seq
|
||||
INCREMENT 1
|
||||
START 1
|
||||
MINVALUE 1
|
||||
MAXVALUE 2147483647
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.mail_accounts_id_seq
|
||||
OWNER TO {{ db_user }};
|
||||
|
||||
CREATE SEQUENCE public.mail_sessions_id_seq
|
||||
INCREMENT 1
|
||||
START 1
|
||||
MINVALUE 1
|
||||
MAXVALUE 2147483647
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.mail_sessions_id_seq
|
||||
OWNER TO {{ db_user }};
|
||||
|
||||
CREATE SEQUENCE public.sprav_id_seq
|
||||
INCREMENT 1
|
||||
START 1
|
||||
MINVALUE 1
|
||||
MAXVALUE 2147483647
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.sprav_id_seq
|
||||
OWNER TO {{ db_user }};
|
||||
|
||||
|
||||
CREATE SEQUENCE public.filter_id_seq
|
||||
INCREMENT 1
|
||||
START 1
|
||||
MINVALUE 1
|
||||
MAXVALUE 2147483647
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.filter_id_seq
|
||||
OWNER TO mail_alarm;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.alarm
|
||||
(
|
||||
id integer NOT NULL DEFAULT nextval('alarm_id_seq'::regclass),
|
||||
mail_account_id integer,
|
||||
remote_ip inet,
|
||||
country_code character(6) COLLATE pg_catalog."default",
|
||||
last_time character varying COLLATE pg_catalog."default",
|
||||
last_check_timestamp timestamp without time zone,
|
||||
alarm_type integer,
|
||||
alarm_action boolean,
|
||||
action_timestamp timestamp without time zone,
|
||||
mail_action_timestamp timestamp without time zone,
|
||||
mail2_action_timestamp timestamp without time zone,
|
||||
CONSTRAINT alarm_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE public.alarm
|
||||
OWNER to {{ db_user }};
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.mail_accounts
|
||||
(
|
||||
id integer NOT NULL DEFAULT nextval('mail_accounts_id_seq'::regclass),
|
||||
client_name character varying(100) COLLATE pg_catalog."default" NOT NULL,
|
||||
client_account character varying(100) COLLATE pg_catalog."default",
|
||||
remote_ip inet,
|
||||
country_code character(3) COLLATE pg_catalog."default",
|
||||
CONSTRAINT mail_accounts_pkey PRIMARY KEY (id, client_name),
|
||||
CONSTRAINT client_name UNIQUE (client_name)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE public.mail_accounts
|
||||
OWNER to {{ db_user }};
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.mail_sessions
|
||||
(
|
||||
id integer NOT NULL DEFAULT nextval('mail_sessions_id_seq'::regclass),
|
||||
mail_account_id integer,
|
||||
remote_ip inet,
|
||||
sessions_count integer,
|
||||
country_code character(3) COLLATE pg_catalog."default",
|
||||
last_time character varying COLLATE pg_catalog."default",
|
||||
last_check_timestamp timestamp without time zone,
|
||||
mail_reason character varying COLLATE pg_catalog."default",
|
||||
CONSTRAINT mail_sessions_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE public.mail_sessions
|
||||
OWNER to {{ db_user }};
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.sprav
|
||||
(
|
||||
id integer NOT NULL DEFAULT nextval('sprav_id_seq'::regclass),
|
||||
name character varying COLLATE pg_catalog."default",
|
||||
sprav_type character(30) COLLATE pg_catalog."default",
|
||||
CONSTRAINT sprav_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE public.sprav
|
||||
OWNER to {{ db_user }};
|
||||
|
||||
|
||||
-- DROP TABLE public.filter;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.filter
|
||||
(
|
||||
id integer NOT NULL DEFAULT nextval('filter_id_seq'::regclass),
|
||||
remote_ip inet NOT NULL,
|
||||
description character varying(100) COLLATE pg_catalog."default",
|
||||
CONSTRAINT filter_pkey PRIMARY KEY (id, remote_ip)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE public.filter
|
||||
OWNER to mail_alarm;
|
||||
|
23
docker-compose.yml
Normal file
23
docker-compose.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
version: '3'
|
||||
|
||||
services:
|
||||
zimbra-alarm:
|
||||
# $IMAGE_PATH и $RELEASE_VERSION определены в .gitlab-ci.yml
|
||||
image: $IMAGE_PATH/zimbra-alarm:$RELEASE_VERSION
|
||||
environment:
|
||||
- ELASTICSEARCH_URL=https://${ELASTIC_USER}:${ELASTIC_PASSWORD}@${ELASTIC_HOST}:9200
|
||||
- PGHOST=${PGHOST:-inf-db01.corp.samsonopt.ru}
|
||||
- PGDATABASE=${PGDATABASE:-mail_alarm}
|
||||
- PGUSER=${PGUSER:-mail_alarm}
|
||||
- PGPASSWORD=${PGPASSWORD}
|
||||
- REQUEST_TIME_RANGE=${REQUEST_TIME_RANGE:-4}
|
||||
- REQUEST_ROWS=${REQUEST_ROWS:-10000}
|
||||
- TZ=Europe/Moscow
|
||||
restart: always
|
||||
build:
|
||||
context: .
|
||||
logging:
|
||||
# driver: "syslog"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "5"
|
7
entrypoint.sh
Normal file
7
entrypoint.sh
Normal file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
set -u
|
||||
|
||||
while true ;do
|
||||
/go/bin/zimbra-alarm --indexname "maillog_mailbox" -timerange "${REQUEST_TIME_RANGE}m" -operation es-request-data -pg-insert -request-rows ${REQUEST_ROWS}
|
||||
sleep 120
|
||||
done
|
32
go.mod
Normal file
32
go.mod
Normal file
|
@ -0,0 +1,32 @@
|
|||
module my-elasticsearch-app
|
||||
|
||||
go 1.19
|
||||
|
||||
require github.com/elastic/go-elasticsearch/v7 v7.17.1
|
||||
|
||||
require (
|
||||
github.com/coreos/go-iptables v0.6.0 // indirect
|
||||
github.com/gonetx/ipset v0.1.0 // indirect
|
||||
github.com/hpcloud/tail v1.0.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/adubkov/go-zabbix v0.0.0-20170118040903-3c6a95ec4fdc
|
||||
github.com/cavaliercoder/go-zabbix v0.0.0-20210304010121-96120c17dd42 // indirect
|
||||
github.com/elastic/go-elasticsearch/v8 v8.3.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.12.0
|
||||
github.com/jackc/pgx/v4 v4.16.1 // indirect
|
||||
github.com/jackc/pgx/v5 v5.0.0-beta.3
|
||||
github.com/nixys/nxs-go-zabbix/v5 v5.0.0 // indirect
|
||||
github.com/opensearch-project/opensearch-go/v2 v2.0.0 // indirect
|
||||
github.com/rday/zabbix v0.0.0-20170517233925-1cf60ccd42f9 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
232
go.sum
Normal file
232
go.sum
Normal file
|
@ -0,0 +1,232 @@
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/adubkov/go-zabbix v0.0.0-20170118040903-3c6a95ec4fdc h1:gqqI4ZPa7uwK+gX9Zgk2AweAh+2dX0FpETcXTsA2TrE=
|
||||
github.com/adubkov/go-zabbix v0.0.0-20170118040903-3c6a95ec4fdc/go.mod h1:ihDXRSVen590YHlXIrv00CcmRrL6pUho/Iwm3ZmM8n8=
|
||||
github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
|
||||
github.com/cavaliercoder/go-zabbix v0.0.0-20210304010121-96120c17dd42 h1:S+MAp8YOH/TkyOTHa1/z/reraTs7fJL0xBOx5+3bA78=
|
||||
github.com/cavaliercoder/go-zabbix v0.0.0-20210304010121-96120c17dd42/go.mod h1:o9iZ0ep18zjkTdG1yoCmBZSMAWo2qUXVMxqmEl+6GLo=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elastic/elastic-transport-go/v8 v8.0.0-20211216131617-bbee439d559c h1:onA2RpIyeCPvYAj1LFYiiMTrSpqVINWMfYFRS7lofJs=
|
||||
github.com/elastic/elastic-transport-go/v8 v8.0.0-20211216131617-bbee439d559c/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI=
|
||||
github.com/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA=
|
||||
github.com/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg=
|
||||
github.com/elastic/go-elasticsearch/v7 v7.5.1-0.20210322101442-a3e161131102 h1:o4HAbzLv9EOWc6ue8fyB00AcE78Y3fp8FD9RYy0z73M=
|
||||
github.com/elastic/go-elasticsearch/v7 v7.5.1-0.20210322101442-a3e161131102/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.1 h1:49mHcHx7lpCL8cW1aioEwSEVKQF3s+Igi4Ye/QTWwmk=
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.1/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
|
||||
github.com/elastic/go-elasticsearch/v8 v8.3.0 h1:RF4iRbvWkiT6UksZ+OwSLeCEtBg/HO8r88xNiSmhb8U=
|
||||
github.com/elastic/go-elasticsearch/v8 v8.3.0/go.mod h1:Usvydt+x0dv9a1TzEUaovqbJor8rmOHy5dSmPeMAE2k=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gonetx/ipset v0.1.0 h1:LFkRdTbedg2UYXFN/2mOtgbvdWyo+OERrwVbtrPVuYY=
|
||||
github.com/gonetx/ipset v0.1.0/go.mod h1:AwNAf1Vtqg0cJ4bha4w1ROX5cO/8T50UYoegxM20AH8=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8=
|
||||
github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y=
|
||||
github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs=
|
||||
github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
|
||||
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y=
|
||||
github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ=
|
||||
github.com/jackc/pgx/v5 v5.0.0-beta.3 h1:/fvyxKQQVrEgD6elYv2Fa0L16ytVn8Ll18k1XQ/yaGw=
|
||||
github.com/jackc/pgx/v5 v5.0.0-beta.3/go.mod h1:QJ8xU09HYKHOccHeisi/6sXeRG4dd3AxuV7cmKET4WA=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle/v2 v2.0.0-beta.1/go.mod h1:itE7ZJY8xnoo0JqJEpSMprN0f+NQkMCuEV/N9j8h0oc=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw=
|
||||
github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/nixys/nxs-go-zabbix/v5 v5.0.0 h1:AvVNPs/w2xSampQn25KnvNOx49O9mE5KuIlLrSTXpnE=
|
||||
github.com/nixys/nxs-go-zabbix/v5 v5.0.0/go.mod h1:9R4cq2L8wHvVAz0ZfNIvzyXRUGCsrJOd7HvWiRoz6TI=
|
||||
github.com/opensearch-project/opensearch-go/v2 v2.0.0 h1:Ij3CpuHwey29cYPVMgi5h1pWBH2O0JaTXsa4c7pqhK4=
|
||||
github.com/opensearch-project/opensearch-go/v2 v2.0.0/go.mod h1:G3kbnV+SeVf4QTbNcrT7Ga3FCsavtp5NQfdRelJikIQ=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rday/zabbix v0.0.0-20170517233925-1cf60ccd42f9 h1:ARUuqpY5LjSR4//P6TolxJP81zjO+qNuOlEVD4mvIfs=
|
||||
github.com/rday/zabbix v0.0.0-20170517233925-1cf60ccd42f9/go.mod h1:IIFS/h+mpikvp6WVUQwg9fO8IlGy7q3LE1wt3MeWhvg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
|
||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
1107
zimbra-alarm.go
Normal file
1107
zimbra-alarm.go
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user