warp

package module
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2026 License: MIT Imports: 20 Imported by: 0

README

English | 日本語









WARP









Warp is an outbound transparent SMTP proxy. SMTP level logging is possible, and throttling is detected from MX response time and other comprehensive response status. Additionally, it is possible to use different IP addresses for outgoing communications based on internal reputation. https://warp.linyo.ws


GitHub Release

The Problem

Operating email infrastructure at scale comes with significant challenges:

  • No visibility — You can't see what's being sent, to whom, or how the remote server responds
  • Deliverability issues — Throttling and blocklisting happen silently; you only find out when users complain
  • No filtering layer — Compromised accounts or misconfigured applications send spam or phishing emails before anyone notices
  • IP reputation management — A single bad sender can damage the reputation of your entire IP range
  • Compliance gaps — Auditing outbound email requires bolting on external tools that don't integrate cleanly

How Warp Solves It

Warp deploys as a transparent proxy using Linux's SO_ORIGINAL_DST — it intercepts SMTP connections at the network level, meaning zero changes to your existing mail clients or applications. Once in place, Warp provides:

Observability

Every SMTP command and response is captured in real time. You can log to files, MySQL, SQLite, or send notifications to Slack — all through a simple plugin system. Connection metadata (sender, recipient, HELO hostname, elapsed time) is automatically extracted and structured for analysis.

Filtering

Warp can buffer the entire message during the DATA phase and pass it to a filter hook before relaying. Your filter logic decides what happens next:

Action Behavior
Relay Pass the message through to the destination server as-is
Reject Return an SMTP error to the sender — the message never reaches the destination
Add Header Modify the message (e.g., add X-Spam-Score headers) and then relay

Deliverability Intelligence

By measuring the time between connection and the server's 354 response, Warp detects MX throttling patterns. Combined with SMTP response codes, you get a comprehensive view of how remote servers are treating your mail.

IP Routing

Warp supports configurable outbound IP addresses, enabling you to route mail through different IPs based on sender reputation, recipient domain, or any custom logic.

Architecture

Warp Architecture

                    Transparent Proxy (iptables REDIRECT)
                    ┌─────────────────────────────┐
  SMTP Client ────▶ │           Warp              │ ────▶ Destination MX
                    │                             │
                    │  ┌─────────┐  ┌──────────┐  │
                    │  │Upstream │  │Downstream│  │
                    │  │Mediator │  │Mediator  │  │
                    │  └────┬────┘  └────┬─────┘  │
                    │       │            │        │
                    │  ┌────▼────────────▼─────┐  │
                    │  │    Hook System         │  │
                    │  │  ┌──────┐ ┌────────┐  │  │
                    │  │  │ Log  │ │ Filter │  │  │
                    │  │  └──────┘ └────────┘  │  │
                    │  └───────────────────────┘  │
                    └─────────────────────────────┘

Key components:

  • Server — Listens for incoming TCP connections and extracts the original destination using SO_ORIGINAL_DST
  • Pipe — Manages bidirectional data flow between client and server with upstream/downstream mediators
  • Mediators — Inspect and transform SMTP traffic in each direction, extracting metadata (MAIL FROM, RCPT TO, HELO) and handling STARTTLS negotiation
  • Hook System — Extensible plugin architecture for logging (AfterComm, AfterConn) and filtering (BeforeRelay)

STARTTLS Handling

Warp transparently handles TLS negotiation: it strips STARTTLS from the server's EHLO response to the client, then initiates its own TLS connection to the destination server. This allows Warp to inspect SMTP traffic while maintaining encrypted delivery.

Getting Started

Installation

go install github.com/linyows/warp/cmd/warp@latest

Or download a pre-built binary from Releases.

Basic Usage

warp -ip 0.0.0.0 -port 10025 -verbose

iptables Setup (Transparent Proxy)

Redirect outgoing SMTP traffic to Warp:

iptables -t nat -A OUTPUT -p tcp --dport 25 -j REDIRECT --to-port 10025

Command Line Options

Flag Default Description
-ip 127.0.0.1 Listen IP address
-port (required) Listen port
-outbound-ip 0.0.0.0 Source IP for outgoing connections
-plugins Comma-separated plugin names: mysql, sqlite, file, slack
-message-size-limit 10240000 Maximum message size in bytes (~10MB)
-verbose false Enable detailed logging
-version false Show version information

Example: Full Setup

# Start Warp with MySQL logging and Slack notifications
warp -ip 0.0.0.0 -port 10025 \
     -outbound-ip 203.0.113.10 \
     -plugins mysql,slack \
     -message-size-limit 20480000 \
     -verbose

Plugin System

Warp uses Go's plugin system to load .so files from /opt/warp/plugins/ (or the path specified by PLUGIN_PATH environment variable). Each plugin implements the Hook interface:

type Hook interface {
    Name() string
    AfterInit()
    AfterComm(*AfterCommData)  // Called after each SMTP command/response
    AfterConn(*AfterConnData)  // Called when a connection closes
}

For message filtering, implement the FilterHook interface:

type FilterHook interface {
    Hook
    BeforeRelay(*BeforeRelayData) *FilterResult
}

Built-in Plugins

Plugin Description Environment Variables
file Logs all SMTP communications to a JSON file FILE_PATH
mysql Stores communications and connections in MySQL DSN
sqlite Stores communications and connections in SQLite DSN
slack Sends connection notifications to a Slack channel SLACK_TOKEN, SLACK_CHANNEL

Building Plugins

cd plugins/file
go build -buildmode=plugin -o /opt/warp/plugins/file.so

MySQL Setup

Use the provided schema to set up the database:

mysql < misc/setup.sql

Use Cases

  • Email Gateway — Centralized SMTP inspection point for your organization
  • Spam & Phishing Prevention — Filter outbound messages before they damage your reputation
  • Compliance & Auditing — Log every outbound email with full SMTP-level detail
  • Data Loss Prevention (DLP) — Inspect message content for sensitive data before delivery
  • Deliverability Monitoring — Track MX response times and detect throttling in real time
  • IP Reputation Management — Route mail through different IPs based on sender behavior
  • Development & Debugging — Capture and inspect SMTP traffic during development

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Author

linyows

License

MIT

Documentation

Index

Constants

View Source
const SO_ORIGINAL_DST = 80
View Source
const (
	TimeFormat string = "2006-01-02T15:04:05.999999"
)

Variables

This section is empty.

Functions

func GenID added in v0.5.0

func GenID() ulid.ULID

func WaitForServerListen added in v0.7.0

func WaitForServerListen(ip string, port int)

Types

type AfterCommData added in v0.5.0

type AfterCommData struct {
	ConnID     string
	OccurredAt time.Time
	Data
	Direction
}

type AfterConnData added in v0.5.0

type AfterConnData struct {
	ConnID     string
	OccurredAt time.Time
	MailFrom   []byte
	MailTo     []byte
	Elapse
}

type BeforeRelayData added in v0.17.0

type BeforeRelayData struct {
	ConnID   string
	MailFrom []byte
	MailTo   []byte
	SenderIP string
	Helo     []byte
	// Message is the full message (headers + body) in SMTP DATA wire format.
	// It is dot-stuffed as received on the wire and does NOT include the
	// terminating "\r\n.\r\n" sequence.
	Message []byte
}

BeforeRelayData contains the data available to filter hooks before relaying.

type Data added in v0.5.0

type Data []byte

type Direction added in v0.2.0

type Direction string

type Elapse added in v0.6.0

type Elapse int

func (Elapse) String added in v0.6.0

func (e Elapse) String() string

type FilterAction added in v0.17.0

type FilterAction int

FilterAction represents the action to take after filtering.

const (
	FilterRelay     FilterAction = iota // Relay as-is
	FilterReject                        // Reject with SMTP error response
	FilterAddHeader                     // Add/modify headers and relay
)

type FilterHook added in v0.17.0

type FilterHook interface {
	Hook
	BeforeRelay(*BeforeRelayData) *FilterResult
}

FilterHook extends Hook with a BeforeRelay method called during the DATA phase.

type FilterResult added in v0.17.0

type FilterResult struct {
	Action FilterAction
	// Message is the modified message for FilterAddHeader. It MUST be in SMTP
	// DATA wire format (dot-stuffed) and MUST NOT contain the terminator
	// "\r\n.\r\n". The terminator is appended automatically after relay.
	Message []byte
	// Reply is the SMTP reply for FilterReject (e.g. "550 5.7.1 Spam detected").
	// Must be a single line without CR/LF characters; any CR/LF will be stripped.
	Reply string
}

FilterResult represents the result of a filter hook.

type Flow added in v0.5.0

type Flow int

type Hook added in v0.5.0

type Hook interface {
	Name() string
	AfterInit()
	AfterComm(*AfterCommData)
	AfterConn(*AfterConnData)
}

type Mediator added in v0.2.0

type Mediator func([]byte, int) ([]byte, int, bool)

type Pipe

type Pipe struct {
	// contains filtered or unexported fields
}

func (*Pipe) Close added in v0.15.0

func (p *Pipe) Close()

func (*Pipe) Do

func (p *Pipe) Do()

type Plugins added in v0.10.0

type Plugins struct {
	// contains filtered or unexported fields
}

type ReceivedMessage added in v0.17.0

type ReceivedMessage struct {
	Helo     string
	MailFrom string
	RcptTo   []string
	Data     []byte
}

ReceivedMessage represents a message received by the test SMTP server.

type SMTPClient added in v0.7.0

type SMTPClient struct {
	IP   string
	Port int
}

func (*SMTPClient) SendEmail added in v0.7.0

func (c *SMTPClient) SendEmail() error

type SMTPConn added in v0.7.0

type SMTPConn struct {
	// contains filtered or unexported fields
}

type SMTPServer added in v0.7.0

type SMTPServer struct {
	IP        string
	Port      int
	Hostname  string
	OnMessage func(ReceivedMessage)
	// contains filtered or unexported fields
}

func (*SMTPServer) Serve added in v0.7.0

func (s *SMTPServer) Serve() error

type Server

type Server struct {
	Addr         string
	Port         int
	Hooks        []Hook
	Plugins      []string
	OutboundAddr string
	Verbose      bool

	MessageSizeLimit int
	// contains filtered or unexported fields
}

func (*Server) HandleConnection

func (s *Server) HandleConnection(conn net.Conn)

func (*Server) OriginalAddrDst added in v0.2.0

func (s *Server) OriginalAddrDst(conn net.Conn) (*net.TCPAddr, error)

func (*Server) Start

func (s *Server) Start() error

Directories

Path Synopsis
cmd
warp command
plugins
file command
mysql command
slack command
sqlite command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL