GO实现基于命令行的简单IPS程序代码

 更新时间:2024年12月28日 11:21:03   作者:星星猫  
本文介绍了入侵防御系统IPS的工作原理和实现,IPS通过网络流量监控和实时响应,防止网络攻击,通过使用Go语言实现一个简单的IPS示例程序,展示了如何获取本地IP地址和探测网络中其他设备的IP地址,包括如何定义和加载规则文件,以及如何检测IP对相应端口的访问是否达到规定阈值

入侵防御系统

IPS(Intrusion Prevention System)即入侵防御系统,主要用于实时检查和阻止网络入侵。与入侵检测系统(IDS)不同,IPS通常部署在网络的关键路径上,实时监控网络流量,并在发现攻击时立即采取响应措施,如丢弃恶意数据包、封锁攻击源IP地址等。

IPS的工作原理

IPS通过直接嵌入到网络流量中实现主动防御。它通过一个网络端口接收来自外部系统的流量,经过检查确认其中不包含异常活动或可疑内容后,再通过另一个端口传送到内部系统中。有问题的数据包以及所有来自同一数据流的后续数据包都会在IPS设备中被清除掉。

GO实现IPS

下面我们用 Go 语言编写,一个可以在命令行中获取并打印本地 IP 地址(基于常见网络接口)的示例程序,这里主要是获取 IPv4 地址进行展示,示例代码使用了标准库中的 net 包:

获取本地网络接口上绑定的 IP 

package main

import (
    "fmt"
    "net"
)

func main() {
    addrs, err := net.InterfaceAddrs()
    if err!= nil {
        fmt.Printf("获取网络接口地址失败: %v\n", err)
        return
    }

    for _, addr := range addrs {
        ipNet, ok := addr.(*net.IPNet)
        if ok &&!ipNet.IP.IsLoopback() && ipNet.IP.To4()!= nil {
            fmt.Println("IP地址:", ipNet.IP.String())
        }
    }
}

运行

  1. 确保已经安装了 Go 环境(Go 1.10 及以上版本)。
  2. 将上述代码保存到一个以 .go 为后缀的文件中,比如 ips.go。
  3. 打开命令行,切换到该文件所在的目录。
  4. 运行命令 go run ips.go,程序就会执行并输出找到的本地非回环的 IPv4 地址信息。

也可编译后运行

go build ips.go

然后运行生成的可执行文件(在 Windows 上是 .exe 后缀的文件,在 Linux、macOS 等系统上就是普通的二进制文件)也能看到相应的 IP 地址输出。

请注意:这里只是简单获取本地网络接口上绑定的 IP 示例

 对于IPS而言,他要检测的是网络中的流量(比如探测网络中其他设备 IP 等)这需要进一步扩展代码,例如利用 net.Dial 等去做网络连接测试、IP 扫描等操作。

探测网络中其他设备 IP

这里只是通过简单的 ICMP 即 ping 操作概念类似的简单探测

package main

import (
    "fmt"
    "net"
    "os"
    "sync"
    "time"
)

func PingIP(ip string, wg *sync.WaitGroup, result chan<- string) {
    defer wg.Done()
    conn, err := net.DialTimeout("ip4:icmp", ip, time.Second*2)
    if err == nil {
        conn.Close()
        result <- ip
    }
}

func main() {
    if len(os.Args)!= 2 {
        fmt.Println("请输入要扫描的网段,例如 192.168.1.0/24")
        return
    }
    _, ipnet, err := net.ParseCIDR(os.Args[1])
    if err!= nil {
        fmt.Printf("解析网段失败: %v\n", err)
        return
    }

    var wg sync.WaitGroup
    result := make(chan string)

    for ip := ipnet.IP.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
        wg.Add(1)
        go PingIP(ip.String(), &wg, result)
    }

    go func() {
        wg.Wait()
        close(result)
    }()

    for aliveIP := range result {
        fmt.Println("存活IP:", aliveIP)
    }
}

func inc(ip net.IP) {
    for j := len(ip) - 1; j >= 0; j-- {
        ip[j]++
        if ip[j] > 0 {
            break
        }
    }
}

在命令行中使用这个扩展版本时,可以像这样运行(假设编译后的可执行文件名为 ips):

./ips 192.168.1.0/24

上述命令会尝试去探测指定网段 192.168.1.0/24 内的 IP 地址哪些是存活的(可以响应 ICMP 请求的,类似 ping 通的概念),并打印出存活的 IP 地址。

增加规则文件(rules.json)

首先我们设定一个规则文件,用json的方式来保存规则

[
    {
        "id": "1001",
        "description": "SSH暴力破解检测",
        "protocol": "tcp",
        "dst_port": 22,
        "action": "block",
        "threshold": 5,
        "time_window": 60
    },
    {
        "id": "1002",
        "description": "RDP暴力破解检测",
        "protocol": "tcp",
        "dst_port": 3389,
        "action": "block",
        "threshold": 5,
        "time_window": 60
    },
    {
        "id": "1003",
        "description": "MySQL暴力破解检测",
        "protocol": "tcp",
        "dst_port": 3306,
        "action": "block",
        "threshold": 5,
        "time_window": 60
    }
]

然后我们写一个go文件,来检测 IP 对相应端口的访问是否达到规则中定义的暴力破解阈值情况

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net"
    "os"
    "path/filepath"
    "sync"
    "time"
)

// Rule结构体表示一条安全规则
type Rule struct {
    ID          string  `json:"id"`
    Description string  `json:"description"`
    Protocol    string  `json:"protocol"`
    DstPort     int     `json:"dst_port"`
    Action      string  `json:"action"`
    Threshold   int     `json:"threshold"`
    TimeWindow  int     `json:"time_window"`
}

// LoadRules从文件加载安全规则
func LoadRules(filePath string) ([]*Rule, error) {
    content, err := ioutil.ReadFile(filePath)
    if err!= nil {
        return nil, fmt.Errorf("读取规则文件失败: %v", err)
    }
    var rules []*Rule
    err = json.Unmarshal(content, &rules)
    if err!= nil {
        return nil, fmt.Errorf("解析规则文件失败: %v", err)
    }
    return rules, nil
}

// ConnectionRecord记录IP的连接记录(简化示例,仅记录次数)
type ConnectionRecord struct {
    mu         sync.Mutex
    connections map[string]int
}

func NewConnectionRecord() *ConnectionRecord {
    return &ConnectionRecord{
        connections: make(map[string]int),
    }
}

func (cr *ConnectionRecord) Record(ip net.IP, port int) {
    cr.mu.Lock()
    key := fmt.Sprintf("%s:%d", ip.String(), port)
    cr.connections[key]++
    cr.mu.Unlock()
}

func (cr *ConnectionRecord) CheckViolation(rules []*Rule) []*Rule {
    var violatedRules []*Rule
    cr.mu.Lock()
    now := time.Now()
    for _, rule := range rules {
        for key, count := range cr.connections {
            parts := strings.Split(key, ":")
            ip := net.ParseIP(parts[0])
            port := atoi(parts[1])
            if port == rule.DstPort && count >= rule.Threshold {
                // 这里简单判断次数达到阈值就算违规,实际可能需考虑时间窗口等更复杂逻辑细化
                violatedRules = append(violatedRules, rule)
            }
        }
    }
    cr.mu.Unlock()
    return violatedRules
}

func atoi(s string) int {
    n, _ := fmt.Sscanf(s, "%d", &n)
    return n
}

func main() {
    // 获取当前目录下的rules.json作为配置文件路径(可根据实际调整)
    currentDir, err := os.Getwd()
    if err!= nil {
        fmt.Printf("获取当前目录失败: %v\n", err)
        return
    }
    configFilePath := filepath.Join(currentDir, "rules.json")

    rules, err := LoadRules(configFilePath)
    if err!= nil {
        fmt.Printf("加载规则失败: %v\n", err)
        return
    }

    targetIPNet := &net.IPNet{}
    _, targetIPNet, err = net.ParseCIDR("192.168.1.0/24")
    if err!= nil {
        fmt.Printf("解析目标IP网段失败: %v\n", err)
        return
    }

    record := NewConnectionRecord()

    // 模拟IP对内网端口的连接访问(这里简单循环增加连接次数示例)
    for i := 0; i < 10; i++ {
        for ip := targetIPNet.IP.Mask(targetIPNet.Mask); targetIPNet.Contains(ip); inc(ip) {
            // 简单模拟多次访问各规则关注的端口,实际场景会根据真实网络连接情况记录
            for _, rule := range rules {
                record.Record(ip, rule.DstPort)
            }
        }
    }

    violatedRules := record.CheckViolation(rules)
    for _, violatedRule := range violatedRules {
        fmt.Printf("IP段内存在疑似违反规则 %s 的情况,规则描述:%s\n", violatedRule.ID, violatedRule.Description)
    }
}

func inc(ip net.IP) {
    for j := len(ip) - 1; j >= 0; j-- {
        ip[j]++
        if ip[j] > 0 {
            break
        }
    }
}
  1. 定义规则结构体和相关操作函数:
  • 首先定义了 Rule 结构体,其字段与 JSON 格式的规则文件中的各个属性相对应,用于表示一条安全规则。
  • LoadRules 函数用于读取指定路径的 JSON 规则文件,并将其解析为 Rule 结构体的切片,若读取或解析过程出现错误则返回相应的错误信息。
  1. 定义连接记录结构体及相关方法:
  • ConnectionRecord 结构体用于记录 IP 地址对不同端口的连接情况,内部使用一个互斥锁(sync.Mutex)来保证并发安全,通过 Record 方法记录每个 IP 和端口的连接次数,使用 CheckViolation 方法来检查当前的连接记录是否违反了给定的规则(这里只是简单根据连接次数是否达到阈值判断,实际可进一步完善考虑时间窗口等更多细节)。
  1. 主函数逻辑:
  • 先获取当前目录下规则配置文件(rules.json)的路径(可按需修改为其他路径),调用 LoadRules 函数加载规则列表。
  • 接着解析要检测的目标 IP 网段(示例中为 192.168.1.0/24,可以根据实际情况更改),创建一个 ConnectionRecord 实例来记录连接情况。
  • 然后通过循环模拟 IP 对内网各端口的访问(这里只是简单循环增加访问次数示意,实际需要结合真实的网络连接情况来记录),并调用 ConnectionRecord 的 Record 方法记录每次的访问情况。
  • 最后调用 ConnectionRecord 的 CheckViolation 方法检查是否有违反规则的情况,若有则打印出相应的违规规则信息。

注意

这里的代码仅是抛砖引玉,其中的规则检查逻辑,尤其是针对时间窗口的处理比较简化,在实际应用场景中,你可能需要精确地记录每个连接的时间戳,并按照时间窗口准确判断是否在指定时间段内达到了阈值等情况,以实现更符合实际需求的检测逻辑。

模拟的 IP 访问场景也非常简单,只是为了演示功能而进行的简单循环增加访问次数,实际需要对接真实的网络流量监控等相关机制来准确记录 IP 的访问情况。

到此这篇关于GO实现基于命令行的简单IPS程序代码的文章就介绍到这了,更多相关GO实现基于命令行的简单IPS内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go 如何使用原始套接字捕获网卡流量

    Go 如何使用原始套接字捕获网卡流量

    为了减少对环境的依赖可以使用原始套接字捕获网卡流量,然后使用 gopacket 的协议解析功能,这样就省去了解析这部分的工作量,正确性也可以得到保证,同时 CGO 也可以关闭,这篇文章主要介绍了Go 使用原始套接字捕获网卡流量,需要的朋友可以参考下
    2024-07-07
  • Go语言中的反射原理解析与应用

    Go语言中的反射原理解析与应用

    反射(Reflection)是计算机科学中的一个重要概念,它允许程序在运行时检查变量和值,获取它们的类型信息,并且能够修改它们,本文将结合实际案例,详细介绍Go语言中反射的基本概念、关键函数以及使用场景,需要的朋友可以参考下
    2024-10-10
  • 详解Go如何优雅的对时间进行格式化

    详解Go如何优雅的对时间进行格式化

    这篇文章主要为大家详细介绍了Go语言中是如何优雅的对时间进行格式化的,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-06-06
  • 自定义Go Json的序列化方法译文

    自定义Go Json的序列化方法译文

    这篇文章主要为大家介绍了自定义Go Json序列化方法译文,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • golang 实现每隔几分钟执行一个函数

    golang 实现每隔几分钟执行一个函数

    这篇文章主要介绍了golang 实现每隔几分钟执行一个函数,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 一文详解Golang中的匿名变量

    一文详解Golang中的匿名变量

    匿名变量是一种特殊类型的变量,可以简化代码并提高可读性,本文将为大家详细介绍一下golang中匿名变量的定义、特性和使用方法,需要的可以参考下
    2023-09-09
  • golang实现读取excel数据并导入数据库

    golang实现读取excel数据并导入数据库

    Go 语言是一门适合用于编写高效且并发的 Web 应用程序的编程语言,同时也可以使用它进行数据处理和分析,本文主要介绍了如何通过go语言实现读取excel数据并导入数据库,感兴趣的小伙伴可以了解下
    2025-04-04
  • Golang中生成随机字符串并复制到粘贴板的方法

    Golang中生成随机字符串并复制到粘贴板的方法

    这篇文章主要介绍了Golang中生成随机字符串并复制到粘贴板的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 利用golang实现pdf中自动换行的表格

    利用golang实现pdf中自动换行的表格

    这篇文章主要给大家介绍了如何利用golang实现pdf中自动换行的表格,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02
  • golang并发锁使用详解

    golang并发锁使用详解

    这篇文章主要介绍了golang并发锁使用详解的相关资料,需要的朋友可以参考下
    2023-02-02

最新评论