IP throttling, also known as rate limiting, is a technique used to control the rate of requests from a client to a server. It helps prevent abuse, ensure fair usage of resources, and protect against denial-of-service attacks. In this article, we’ll explore how to implement IP throttling in Go using the net/http package and the golang.org/x/time/rate package, which provides a rate limiter implementation.

Prerequisites

Before we proceed, make sure you have Go installed on your system. You can download and install it from the official Go website.

Setting up the Project

First, create a new directory for your project and initialize it as a Go module:

mkdir ip-throttling-example
cd ip-throttling-example
go mod init ip-throttling-example

Next, install the golang.org/x/time/rate package:

go get golang.org/x/time/rate

Implementing IP Throttling

Now, let’s create a Go program main.go that implements IP throttling using the net/http and golang.org/x/time/rate packages.

Example Code:

package main

import (
    "fmt"
    "net"
    "net/http"
    "sync"

    "golang.org/x/time/rate"
)

// IPRateLimiter represents an IP rate limiter.
type IPRateLimiter struct {
    ips     map[string]*rate.Limiter
    mu      *sync.RWMutex
    limiter *rate.Limiter
}

// NewIPRateLimiter creates a new instance of IPRateLimiter with the given rate limit.
func NewIPRateLimiter(r rate.Limit, burst int) *IPRateLimiter {
    return &IPRateLimiter{
        ips:     make(map[string]*rate.Limiter),
        mu:      &sync.RWMutex{},
        limiter: rate.NewLimiter(r, burst),
    }
}

// Allow checks if the request from the given IP is allowed.
func (lim *IPRateLimiter) Allow(ip string) bool {
    lim.mu.RLock()
    rl, exists := lim.ips[ip]
    lim.mu.RUnlock()

    if !exists {
        lim.mu.Lock()
        rl, exists = lim.ips[ip]
        if !exists {
            rl = rate.NewLimiter(lim.limiter.Limit(), lim.limiter.Burst())
            lim.ips[ip] = rl
        }
        lim.mu.Unlock()
    }

    return rl.Allow()
}

func main() {
    // Create a new IP rate limiter with a rate limit of 1 request per second and a burst limit of 3 requests.
    limiter := NewIPRateLimiter(1, 3)

    // Create an HTTP handler function that applies IP rate limiting.
    handler := func(w http.ResponseWriter, r *http.Request) {
        ip, _, _ := net.SplitHostPort(r.RemoteAddr)
        if !limiter.Allow(ip) {
            http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
            return
        }
        fmt.Fprintf(w, "Hello, your request from IP %s is allowed.\n", ip)
    }

    // Register the handler function with the / endpoint.
    http.HandleFunc("/", handler)

    // Start the HTTP server on port 8080.
    fmt.Println("Server listening on :8080")
    http.ListenAndServe(":8080", nil)
}

In this example:

  • We define an IPRateLimiter struct that represents an IP rate limiter. It contains a map of IP addresses to rate limiters (ips), a mutex (mu) to synchronize access to the map, and a default rate limiter (limiter) for IPs that are not in the map.
  • The NewIPRateLimiter function creates a new instance of IPRateLimiter with the given rate limit and burst limit.
  • The Allow method checks if the request from the given IP address is allowed based on the rate limiter associated with that IP. If the IP is not in the map, a new rate limiter is created and added to the map.
  • In the main function, we create a new instance of IPRateLimiter with a rate limit of 1 request per second and a burst limit of 3 requests.
  • We define an HTTP handler function that applies IP rate limiting. It extracts the IP address from the request, checks if the request is allowed using the rate limiter, and responds accordingly.
  • Finally, we register the handler function with the / endpoint and start an HTTP server listening on port 8080.

Testing the Implementation

To test the implementation, start the Go server by running the following command:

go run .

Open your web browser and navigate to http://localhost:8080. You should see a message indicating that your request is allowed. If you refresh the page multiple times within a second, you’ll eventually receive a 429 Too Many Requests response, indicating that you’ve exceeded the rate limit.

regular

Conclusion

In this article, we explored how to implement IP throttling, also known as rate limiting, in Go using the net/http package and the golang.org/x/time/rate package. We created a custom IP rate limiter that tracks requests from different IP addresses and applies rate limiting based on the specified rate limit and burst limit. By implementing IP throttling, you can control the rate of requests from clients, prevent abuse, and ensure fair usage of resources in your Go applications.

The best way to Fix a problem is to fix it before it’s a problem.
Happy coding! 🚀