Skip to content

KarpelesLab/swnat

Repository files navigation

swnat - Software NAT Library for Go

GoDoc

A pure Go implementation of a software NAT (Network Address Translation) engine with support for TCP, UDP, and ICMP protocols.

Features

  • IPv4 support (with IPv6 structure ready for future implementation)
  • TCP, UDP, and ICMP protocol handling
  • Connection tracking with state management
  • Namespace isolation support
  • Thread-safe connection management
  • Automatic port allocation for outbound connections
  • Packet checksum recalculation
  • Configurable time source for performance optimization
  • Automatic cleanup of expired connections
  • Per-namespace connection limits with LRU eviction
  • TCP session state tracking (automatic cleanup on FIN/RST)
  • Traffic filtering rules (drop packets to specific ports)
  • Destination rewrite rules (redirect traffic to different IPs/ports)
  • Configurable protocol timeouts

Installation

go get github.com/KarpelesLab/swnat

Usage

package main

import (
    "log"
    "net"
    "time"
    "sync/atomic"
    "github.com/KarpelesLab/swnat"
)

func main() {
    // Create a new IPv4 NAT table with external IP
    externalIP := net.ParseIP("203.0.113.1")
    nat := swnat.NewIPv4(externalIP)
    
    // Process outbound packet
    packet := getPacketFromInterface() // Your packet capture logic
    namespace := uintptr(1) // Namespace identifier
    
    err := nat.HandleOutboundPacket(packet, namespace)
    if err == swnat.ErrDropPacket {
        // Packet should be dropped
        return
    } else if err != nil {
        log.Printf("Error processing packet: %v", err)
        return
    }
    
    // Packet has been modified and can be forwarded
    sendPacketToInterface(packet)
    
    // For inbound packets (return traffic)
    inboundPacket := getInboundPacket()
    returnNamespace, err := nat.HandleInboundPacket(inboundPacket)
    if err == swnat.ErrDropPacket {
        // No matching connection found
        return
    } else if err != nil {
        log.Printf("Error processing inbound packet: %v", err)
        return
    }
    
    // Route packet back to the correct namespace
    routeToNamespace(inboundPacket, returnNamespace)
    
    // Periodically cleanup expired connections
    go func() {
        ticker := time.NewTicker(30 * time.Second)
        defer ticker.Stop()
        for now := range ticker.C {
            nat.RunMaintenance(now.Unix())
        }
    }()
}

Performance Optimization

For high-performance scenarios, you can override the time source:

// Use a custom time source that updates less frequently
var currentTime int64
go func() {
    for {
        atomic.StoreInt64(&currentTime, time.Now().Unix())
        time.Sleep(time.Second)
    }
}()

if table, ok := nat.(*swnat.Table[swnat.IPv4]); ok {
    table.Now = func() int64 { return atomic.LoadInt64(&currentTime) }
}

Connection Limits

You can configure the maximum connections per namespace:

if table, ok := nat.(*swnat.Table[swnat.IPv4]); ok {
    // Set maximum 500 connections per namespace
    table.MaxConnPerNamespace = 500
}

When the limit is reached, the oldest connection (by last activity) will be evicted to make room for new connections.

Traffic Filtering and Redirection

// Cast to access IPv4-specific methods
if table, ok := nat.(*swnat.Table[swnat.IPv4]); ok {
    // Drop all SMTP traffic (port 25)
    table.AddDropRule(swnat.ProtocolTCP, 25)
    
    // Redirect DNS traffic from 10.0.0.243:53 to 10.7.0.0:5353
    dnsOrigIP, _ := swnat.ParseIPv4("10.0.0.243")
    dnsNewIP, _ := swnat.ParseIPv4("10.7.0.0")
    table.AddRedirectRule(swnat.ProtocolUDP, dnsOrigIP, 53, dnsNewIP, 5353)
    
    // Configure custom timeouts
    table.TCPTimeout = 3600  // 1 hour
    table.UDPTimeout = 300   // 5 minutes
    table.ICMPTimeout = 60   // 1 minute
}

How It Works

  1. Outbound Packets: When a packet from inside the NAT needs to go out:

    • The library parses the packet headers (IP, TCP/UDP/ICMP)
    • Creates or updates a connection tracking entry
    • Rewrites source IP and port to the external IP and an allocated port
    • Recalculates checksums
    • Returns the modified packet ready for transmission
  2. Inbound Packets: When a return packet arrives:

    • Looks up the connection based on destination port
    • Rewrites destination IP and port back to the original internal values
    • Recalculates checksums
    • Returns the namespace identifier for proper routing
  3. Connection Tracking: The library maintains connection state for all active flows, allowing proper translation of return traffic.

  4. Connection Maintenance: Expired connections are removed during periodic maintenance based on protocol-specific timeouts:

    • TCP: 24 hours (or immediately on next cleanup after FIN/RST)
    • UDP: 3 minutes
    • ICMP: 30 seconds
  5. Connection Limits: Each namespace has a configurable maximum connection limit (default: 200). When reached, the oldest connection is evicted using LRU policy.

Architecture

  • Table[IP]: Main NAT table structure (generic for IPv4/IPv6)
  • Pair[IP]: Connection tracking storage with thread-safe operations
  • Conn[IP]: Individual connection state
  • Packet parsing and manipulation functions for each protocol

Future Enhancements

  • IPv6 support (structure already in place)
  • Port forwarding/DNAT capabilities
  • Connection statistics and monitoring
  • ICMP error message handling (Type 3 - Destination Unreachable)
  • Connection state tracking (SYN, ESTABLISHED, etc.)

License

See LICENSE file for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •