SoFunction
Updated on 2025-04-11

GO implements simple IPS program code based on command line

Intrusion prevention system

IPS (Intrusion Prevention System) is an intrusion prevention system, which is mainly used to check and prevent network intrusion in real time. Unlike intrusion detection systems (IDS), IPS is usually deployed on critical paths of the network, monitoring network traffic in real time, and taking immediate response measures when an attack is discovered, such as discarding malicious packets, blocking the IP address of the attack source, etc.

How IPS works

IPS enables active defense by directly embedding into network traffic. It receives traffic from external systems through one network port, and after checking and confirming that it does not contain abnormal activity or suspicious content, it is then transferred to the internal system through another port. The packets in question, as well as all subsequent packets from the same data stream, will be cleared in the IPS device.

GO implements IPS

Below we write in Go language, a sample program that can obtain and print the local IP address (based on common network interfaces) from the command line. Here we mainly obtain the IPv4 address for display. The sample code uses the net package in the standard library:

Get the IP bound on the local network interface

package main

import (
    "fmt"
    "net"
)

func main() {
    addrs, err := ()
    if err!= nil {
        ("Failed to obtain network interface address: %v\n", err)
        return
    }

    for _, addr := range addrs {
        ipNet, ok := addr.(*)
        if ok &&!() && .To4()!= nil {
            ("IP address:", ())
        }
    }
}

run

  1. Make sure that the Go environment (Go 1.10 and above) is installed.
  2. Save the above code to a file with .go as the suffix, for example.
  3. Open the command line and switch to the directory where the file is located.
  4. Run the command go run, and the program will execute and output the found local non-loopback IPv4 address information.

Can also be compiled and run

go build 

Then run the generated executable file (a file with .exe suffix on Windows, and an ordinary binary file on Linux, macOS and other systems) and you can also see the output of the corresponding IP address.

Please note: Here is just a simple example of obtaining the IP bound on the local network interface

For IPS, what it wants to detect is traffic in the network (such as detecting IP of other devices in the network, etc.), which requires further expansion of the code, such as using    to perform network connection testing, IP scanning and other operations.

Detect other devices in the network IP

Here is just a simple detection similar to the concept of ping operation

package main

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

func PingIP(ip string, wg *, result chan<- string) {
    defer ()
    conn, err := ("ip4:icmp", ip, *2)
    if err == nil {
        ()
        result <- ip
    }
}

func main() {
    if len()!= 2 {
        ("Please enter the network segment to scan, for example 192.168.1.0/24")
        return
    }
    _, ipnet, err := ([1])
    if err!= nil {
        ("Failed to parse the network segment: %v\n", err)
        return
    }

    var wg 
    result := make(chan string)

    for ip := (); (ip); inc(ip) {
        (1)
        go PingIP((), &wg, result)
    }

    go func() {
        ()
        close(result)
    }()

    for aliveIP := range result {
        ("Survival IP:", aliveIP)
    }
}

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

When using this extension on the command line, you can run like this (assuming the compiled executable is called ips):

./ips 192.168.1.0/24

The above command will try to detect which IP addresses in the specified network segment 192.168.1.0/24 (can respond to ICMP requests, similar to the concept of ping) and print out the surviving IP addresses.

Add rule file ()

First, we set a rule file and use json to save the rules

[
    {
        "id": "1001",
        "description": "SSH brute force detection",
        "protocol": "tcp",
        "dst_port": 22,
        "action": "block",
        "threshold": 5,
        "time_window": 60
    },
    {
        "id": "1002",
        "description": "RDP brute-force detection",
        "protocol": "tcp",
        "dst_port": 3389,
        "action": "block",
        "threshold": 5,
        "time_window": 60
    },
    {
        "id": "1003",
        "description": "MySQL brute-force detection",
        "protocol": "tcp",
        "dst_port": 3306,
        "action": "block",
        "threshold": 5,
        "time_window": 60
    }
]

Then we write a Go file to detect whether the IP access to the corresponding port reaches the brute force threshold defined in the rule.

package main

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

// Rule structure represents a security ruletype 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 load security rules from filefunc LoadRules(filePath string) ([]*Rule, error) {
    content, err := (filePath)
    if err!= nil {
        return nil, ("Reading rule file failed: %v", err)
    }
    var rules []*Rule
    err = (content, &rules)
    if err!= nil {
        return nil, ("Parse rule file failed: %v", err)
    }
    return rules, nil
}

// ConnectionRecord records the connection record of the IP (simplified example, only the number of records)type ConnectionRecord struct {
    mu         
    connections map[string]int
}

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

func (cr *ConnectionRecord) Record(ip , port int) {
    ()
    key := ("%s:%d", (), port)
    [key]++
    ()
}

func (cr *ConnectionRecord) CheckViolation(rules []*Rule) []*Rule {
    var violatedRules []*Rule
    ()
    now := ()
    for _, rule := range rules {
        for key, count := range  {
            parts := (key, ":")
            ip := (parts[0])
            port := atoi(parts[1])
            if port ==  && count >=  {
                // Here, it is simply judged that the number of times reaches the threshold is considered a violation. In fact, it may be necessary to consider more complex logical refinement such as time windows.                violatedRules = append(violatedRules, rule)
            }
        }
    }
    ()
    return violatedRules
}

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

func main() {
    // Get the configuration file path in the current directory (can be adjusted according to actual conditions)    currentDir, err := ()
    if err!= nil {
        ("Failed to get the current directory: %v\n", err)
        return
    }
    configFilePath := (currentDir, "")

    rules, err := LoadRules(configFilePath)
    if err!= nil {
        ("Loading rule failed: %v\n", err)
        return
    }

    targetIPNet := &{}
    _, targetIPNet, err = ("192.168.1.0/24")
    if err!= nil {
        ("Failed to parse the target IP segment: %v\n", err)
        return
    }

    record := NewConnectionRecord()

    // Simulate the connection access of IP to intranet ports (this is a simple cycle to increase the number of connections)    for i := 0; i < 10; i++ {
        for ip := (); (ip); inc(ip) {
            // Simply simulate multiple access to the ports that are concerned by each rule. The actual scenario will be recorded based on the real network connection status            for _, rule := range rules {
                (ip, )
            }
        }
    }

    violatedRules := (rules)
    for _, violatedRule := range violatedRules {
        ("There is a suspected violation of the rule %s in the IP segment, rule description: %s\n", , )
    }
}

func inc(ip ) {
    for j := len(ip) - 1; j >= 0; j-- {
        ip[j]++
        if ip[j] > 0 {
            break
        }
    }
}
  1. Define rule structures and related operation functions:
  • First, the Rule structure is defined, and its fields correspond to various properties in the JSON-format rule file to represent a security rule.
  • The LoadRules function is used to read the JSON rule file of the specified path and parse it into a slice of the Rule structure. If there is an error in the reading or parsing process, the corresponding error message will be returned.
  1. Define the connection record structure and related methods:
  • The ConnectionRecord structure is used to record the connection status of the IP address to different ports. It uses a mutex lock () internally to ensure concurrency security. The number of connections of each IP and port is recorded through the Record method, and the CheckViolation method is used to check whether the current connection record violates the given rules (here is just a simple judgment based on whether the number of connections reaches the threshold, and the time window and other details can be further improved to consider).
  1. Main function logic:
  • First get the path of the rule configuration file () in the current directory (can be modified to other paths as needed), and call the LoadRules function to load the rule list.
  • Then parse the target IP segment to be detected (in the example, 192.168.1.0/24, which can be changed according to the actual situation), and create a ConnectionRecord instance to record the connection situation.
  • Then, the IP access to each port in the intranet is simulated through loops (here is just a simple loop to increase the number of accesses, which actually needs to be recorded in combination with the real network connection), and call the Record method of ConnectionRecord to record each access situation.
  • Finally, call the CheckViolation method of ConnectionRecord to check whether there are any violations of the rules. If so, print out the corresponding violation rules information.

Notice

The code here is just a simplified rule check logic, especially the processing of time windows is relatively simplified. In actual application scenarios, you may need to accurately record the timestamp of each connection and accurately judge whether the threshold has been reached within a specified time period according to the time window, etc., to achieve detection logic that is more in line with actual needs.

The simulated IP access scenario is also very simple. It only takes a simple loop to demonstrate the function to increase the number of accesses. In fact, it is necessary to connect with real network traffic monitoring and other related mechanisms to accurately record the IP access situation.

This is the article about GO implementing simple IPS program code based on command line. For more related GO implementing simple IPS content based on command line, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!