121人参与 • 2025-02-14 • Golang
ips(intrusion prevention system)即入侵防御系统,主要用于实时检查和阻止网络入侵。与入侵检测系统(ids)不同,ips通常部署在网络的关键路径上,实时监控网络流量,并在发现攻击时立即采取响应措施,如丢弃恶意数据包、封锁攻击源ip地址等。
ips通过直接嵌入到网络流量中实现主动防御。它通过一个网络端口接收来自外部系统的流量,经过检查确认其中不包含异常活动或可疑内容后,再通过另一个端口传送到内部系统中。有问题的数据包以及所有来自同一数据流的后续数据包都会在ips设备中被清除掉。
下面我们用 go 语言编写,一个可以在命令行中获取并打印本地 ip 地址(基于常见网络接口)的示例程序,这里主要是获取 ipv4 地址进行展示,示例代码使用了标准库中的 net 包:
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())
}
}
}也可编译后运行
go build ips.go
然后运行生成的可执行文件(在 windows 上是 .exe 后缀的文件,在 linux、macos 等系统上就是普通的二进制文件)也能看到相应的 ip 地址输出。
请注意:这里只是简单获取本地网络接口上绑定的 ip 示例
对于ips而言,他要检测的是网络中的流量(比如探测网络中其他设备 ip 等)这需要进一步扩展代码,例如利用 net.dial 等去做网络连接测试、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 地址。
首先我们设定一个规则文件,用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
}
}
}这里的代码仅是抛砖引玉,其中的规则检查逻辑,尤其是针对时间窗口的处理比较简化,在实际应用场景中,你可能需要精确地记录每个连接的时间戳,并按照时间窗口准确判断是否在指定时间段内达到了阈值等情况,以实现更符合实际需求的检测逻辑。
模拟的 ip 访问场景也非常简单,只是为了演示功能而进行的简单循环增加访问次数,实际需要对接真实的网络流量监控等相关机制来准确记录 ip 的访问情况。
到此这篇关于go实现基于命令行的简单ips程序代码的文章就介绍到这了,更多相关go实现基于命令行的简单ips内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论