吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 23550|回复: 138
收起左侧

[原创工具] syslog小型服务器【开源】,可合规检查用

    [复制链接]
红叶落尽 发表于 2021-9-14 11:52
本帖最后由 红叶落尽 于 2021-9-25 09:46 编辑

安全法要求日志保存180天,很多网络设备基本都没法达到这个要求,但是都可以发送syslog,为了保存各个设备的日志文件,就手撸了一个日志服务器。
1、本日志服务器用于接收RFC3164格式的日志,分设备放置于不同文件夹,分日期进行切片存放,一个切片日志6M。有其他需要可以自己调整重新编译。
2、日志服务器默认使用udp 514端口,请在防火墙上设置允许通过。
3、日志服务器会在每天凌晨12点打包上一日的日志,方便进行存储。Windows下可能存在权限问题,右键属性设置一下即可。
PS:
1、该日志服务器解析RFC3164格式的日志,如果需要支持其他格式的日志,可以在源码中调整,可以支持RFC5424和RFC6587。
2、golang写入性能还不错,所以未添加写入缓存,如有需要,可以自行添加。

源码给出 大家可以自己编译。

main.go
[Golang] 纯文本查看 复制代码
package main

import (
        "fmt"
        "io"
        "os"
        "runtime"
        "strconv"
        "strings"
        "time"

        "gopkg.in/mcuadros/go-syslog.v2"
)

var fg string
var hg string
var fdate string
var loghostf map[string]int      //键值对,记录主机和日志切片数据,重新启动程序会自动刷新
var logfilemax = 6 * 1024 * 1024 //6M一个分片
var dt string
var ot string //上一日
var Logbase = "logs"

func main() {
        systype := runtime.GOOS
        if systype == "windows" {
                fg = "\\"
                hg = "\r\n"
        } else {
                fg = "/"
                hg = "\n"
        }
        //dt = "2021-09-13"   //测试数据,正式使用请删除
        dt = time.Now().Format("2006-01-02")
        loghostf = make(map[string]int) //计数器
        _, err := os.Stat(Logbase)
        if os.IsNotExist(err) {
                os.Mkdir(Logbase, os.ModePerm) //建立日志存放文件夹
        }

        channel := make(syslog.LogPartsChannel)
        handler := syslog.NewChannelHandler(channel)

        server := syslog.NewServer() //建立syslog服务器
        server.SetFormat(syslog.RFC3164)  //日志格式
        server.SetHandler(handler)
        server.ListenUDP("0.0.0.0:514")
        server.Boot()

        go func(channel syslog.LogPartsChannel) {
                for logParts := range channel {
                        nt := time.Now().Format("2006-01-02") //日期发生变化时更新日期常数
                        if strings.Compare(dt, nt) != 0 {
                                ot = dt
                                dt = nt
                                if loghostf != nil { //如果日期更新就初始化计数器
                                        for k := range loghostf {
                                                delete(loghostf, k)
                                        }
                                }
                                go Dozipfordel(ot)
                        }
                        doinfile(logParts["hostname"].(string), logParts["content"].(string))
                        fmt.Println(logParts)
                }
        }(channel)
        server.Wait()
}

func doinfile(fhost string, fmsg string) { //写入日志文件
        fpath := logfilestat(fhost)
        f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.ModePerm)
        _, err = io.WriteString(f, fmsg+hg)
        if err != nil {
                fmt.Println("写入文件错误,请检查logs保存路径!")
        }
}

func logfilestat(fhostf string) string { //判断日志文件状态并进行切片
        fnum, fa := loghostf[fhostf]
        if fa == false { //判断键值是否存在
                _, err1 := os.Stat("logs" + fg + fhostf)
                if os.IsNotExist(err1) {
                        os.MkdirAll("logs"+fg+fhostf, os.ModePerm) //新的hostname就新建对应的文件夹
                }
                loghostf[fhostf] = 0 //第一次初始化写入键值
        }
        fp := "logs" + fg + fhostf + fg + dt + "-" + strconv.Itoa(fnum) + ".log"
        ff, err2 := os.Stat(fp)                                        //获取文件状态
        if err2 == nil && fnum == 0 && ff.Size() > int64(logfilemax) { //重新启动时找到正确的切片值
                for fexist(fp) {
                        fnum = fnum + 1
                        fp = "logs" + fg + fhostf + fg + dt + "-" + strconv.Itoa(fnum) + ".log"
                }
                loghostf[fhostf] = fnum
                //fp = "logs" + fg + fhostf + fg + dt + "-" + strconv.Itoa(fnum) + ".log"
        } else {
                if err2 == nil && ff.Size() > int64(logfilemax) { //超过分片大小就新生成一个子文件
                        fnum = fnum + 1
                        loghostf[fhostf] = fnum
                        fp = "logs" + fg + fhostf + fg + dt + "-" + strconv.Itoa(fnum) + ".log"
                }
        }
        return fp
}

func fexist(fp string) bool { //判断文件是否存在
        ff, err := os.Stat(fp)
        if os.IsNotExist(err) || ff.Size() < int64(logfilemax) { //序列号不存在或该序列号对应的文件小于分割文件大小
                return false
        } else {
                return true
        }
}


zip.go
[Asm] 纯文本查看 复制代码
package main

import (
        "archive/zip"
        "io"
        "io/ioutil"
        "os"
        "path/filepath"
        "strings"
)

/**
@files:需要压缩的文件
@compreFile:压缩之后的文件
*/
func Compress_zip(files []*os.File, compreFile *os.File) (err error) {
        zw := zip.NewWriter(compreFile)
        defer zw.Close()
        for _, file := range files {
                err := compress_zip(file, zw)
                if err != nil {
                        return err
                }
                file.Close()
        }
        return nil
}

/**
功能:压缩文件
@file:压缩文件
@prefix:压缩文件内部的路径
@tw:写入压缩文件的流
*/
func compress_zip(file *os.File, zw *zip.Writer) error {
        info, err := file.Stat()
        if err != nil {
                //logs.Error("压缩文件失败:", err.Error())
                return err
        }
        // 获取压缩头信息
        head, err := zip.FileInfoHeader(info)
        if err != nil {
                //logs.Error("压缩文件失败:", err.Error())
                return err
        }
        // 指定文件压缩方式 默认为 Store 方式 该方式不压缩文件 只是转换为zip保存
        head.Method = zip.Deflate
        fw, err := zw.CreateHeader(head)
        if err != nil {
                //logs.Error("压缩文件失败:", err.Error())
                return err
        }
        // 写入文件到压缩包中
        _, err = io.Copy(fw, file)
        file.Close()
        if err != nil {
                //logs.Error("压缩文件失败:", err.Error())
                return err
        }
        return nil
}

/*
获取需要压缩的子文件夹列表
*/
func getDirList(dirpath string) ([]string, error) {
        var dir_list []string
        dirinfo, err := ioutil.ReadDir(dirpath)
        if err == nil {
                for _, dinfo := range dirinfo {
                        if dinfo.IsDir() {
                                dir_list = append(dir_list, dinfo.Name()) //写入文件夹列表
                        }
                }
        }
        return dir_list, err
}

/*
对上一日的日志文件进行压缩后删除文件
*/
func Dozipfordel(ot string) { //上一日日期,进行日志文件压缩
        dps, err := getDirList(Logbase)
        if err == nil {
                for _, dpt := range dps {
                        var zfiles []*os.File
                        var filesname []string
                        err = filepath.Walk(filepath.Join(Logbase, dpt), //便利log子目录下的所有文件,找到对应日期的文件
                                func(path string, f os.FileInfo, err error) error {
                                        if f == nil {
                                                return err
                                        }
                                        if strings.Contains(f.Name(), ot) {
                                                fn := filepath.Join(Logbase, dpt, f.Name()) //获取文件名,添加到文件名队列,用来后面的删除,同时在打开文件句柄
                                                filesname = append(filesname, fn)
                                                of, _ := os.Open(fn)
                                                //defer of.Close()
                                                zfiles = append(zfiles, of)
                                        }
                                        return nil
                                })
                        if len(zfiles) != 0 { //如果文件列表中
                                nf, err := os.OpenFile(filepath.Join(Logbase, dpt, ot)+".zip", os.O_WRONLY|os.O_CREATE, os.ModePerm)
                                //defer nf.Close()
                                if err == nil {
                                        if Compress_zip(zfiles, nf) == nil { //压缩成功后删除源文件
                                                for _, fi := range filesname {
                                                        os.Remove(fi)
                                                }
                                        }
                                }
                        }
                }
        }
}


然后再放一个Windows下的编译好的文件,360可能有误报,自己判断。

syslog服务器.zip

1.43 MB, 下载次数: 1456, 下载积分: 吾爱币 -2 CB

syslogserver for linux.zip

1.47 MB, 下载次数: 288, 下载积分: 吾爱币 -2 CB

免费评分

参与人数 25吾爱币 +29 热心值 +22 收起 理由
chinayrs999 + 1 + 1 我很赞同!
barry1204 + 1 + 1 谢谢@Thanks!
pleasenter + 1 + 1 我很赞同!
imeemi + 1 + 1 谢谢@Thanks!
Coreredhat + 1 + 1 用心讨论,共获提升!
cjhello + 1 + 1 谢谢@Thanks!
z1ex + 1 + 1 正好用到,非常好用。日志分析软件大家有没有推荐的阿。
xuxinxin + 1 + 1 我很赞同!
a520 + 1 + 1 我很赞同!
jiangliu1010 + 1 收藏了@Thanks!
抢师太的秃驴 + 1 + 1 我很赞同!
gz3300 + 1 + 1 谢谢@Thanks!
ldaln + 1 鼓励转贴优秀软件安全工具和文档!
ckawxy + 1 + 1 我很赞同!
AIA + 1 + 1 谢谢@Thanks!
cn199 + 1 鼓励转贴优秀软件安全工具和文档!
13699513436 + 1 用心讨论,共获提升!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
loverix + 1 + 1 鼓励转贴优秀软件安全工具和文档!
bearxja + 1 + 1 我很赞同!
jlzoe + 1 + 1 用心讨论,共获提升!
一大夹子 + 1 谢谢@Thanks!
tuitui + 1 + 1 我很赞同!
egaokiss + 1 + 1 感谢分享这么好的软件,您辛苦了。
ppz + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hurric 发表于 2021-9-14 13:22
确实是个好东西  收藏了  备份一下 https://www.aliyundrive.com/s/wi3yJHGzVJv

免费评分

参与人数 1吾爱币 +1 收起 理由
树下彩虹025 + 1 我很赞同!

查看全部评分

混沌的光与影 发表于 2021-9-15 11:50
红叶落尽 发表于 2021-9-15 10:19
没明白你说的意思,日志文件里面没纪录时间你可以看看是不是协议不匹配。你可以看看代码 我对设备发送的 ...

例如这样
2021-09-15T07:43:35+08:00 2021 FNLY_YanPiao_22.4 %%10STP/6/STP_NOTIFIED_TC: Instance 0's port GigabitEthernet1/0/25 was notified a topology change.
2021-09-15T07:43:38+08:00 2021 FNLY_YanPiao_22.4 %%10STP/6/STP_NOTIFIED_TC: Instance 0's port GigabitEthernet1/0/25 was notified a topology change.
2021-09-15T07:43:55+08:00 2021 FNLY_YanPiao_22.4 %%10STP/6/STP_NOTIFIED_TC: Instance 0's port GigabitEthernet1/0/25 was notified a topology change.
2021-09-15T07:43:58+08:00 2021 FNLY_YanPiao_22.4 %%10STP/6/STP_NOTIFIED_TC: Instance 0's port GigabitEthernet1/0/25 was notified a topology change.
dragontiger 发表于 2021-9-14 12:14
爱新觉罗罹江 发表于 2021-9-14 12:34
好东西,廉价等保
egaokiss 发表于 2021-9-14 12:39
感谢分享这么好的软件,您辛苦了。
Aaron-x 发表于 2021-9-14 13:26
下载了》》》》
QQending 发表于 2021-9-14 13:41
辛苦了,公司的设备默认就不支持180天存储呢
mlhqhj 发表于 2021-9-14 13:55
好东西,感谢发布
winklexp 发表于 2021-9-14 13:57
这个好用,正好需要,用上了,谢谢lz
kenxy 发表于 2021-9-14 13:59
测试一下,好不好用,谢谢楼主的分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-26 09:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表