warp

package module
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2023 License: MIT Imports: 23 Imported by: 0

README







WARP

WARP is an outbound transparent SMTP proxy.









GitHub Release
Go Report Card Go Reference MIT License



For redirect the port need by iptables rule:

iptables -t nat -A OUTPUT -p tcp --dport 25 -j DNAT --to-destination <proxy-ip>:<proxy-port>

Also, the MTA and Proxy must be on the same host to know the DST Address before NAT.

Architecture

Usage

To check the operation, use the sandbox environment with the Vagrantfile in the repository.

warp main 🏄 make
env GOOS=linux GOARCH=amd64 go build -o warp ./cmd/warp/main.go
warp main 🏄 vagrant up
...
warp main 🏄 vagrant status
Current machine states:

sender                    running (virtualbox)
receiver                  running (virtualbox)

Start proxy on sender:

warp main 🏄 vagrant ssh sender
vagrant@sender:~$ /vagrant/warp -ip 192.168.30.30 -port 10025
2021/02/06 14:50:44 warp listens to 192.168.30.30:10025

Send mail on sender:

warp main 🏄 vagrant ssh sender
vagrant@sender:~$ smtp-source -m 1 -s 1 -l 10 -S 'Hi, Receiver from Sender' -f root@sender -t root@receiver localhost:25

Output by proxy on sender:

2021/02/06 14:50:48 connected from 192.168.30.40:57493
2021/02/06 14:50:48 connected to 192.168.30.50:25
2021/02/06 14:50:48 <- 220 receiver ESMTP Postfix (Ubuntu)\r\n
2021/02/06 14:50:48 -> EHLO sender\r\n
2021/02/06 14:50:48 |< 250-receiver\r\n250-PIPELINING\r\n250-SIZE 10240000\r\n250-VRFY\r\n250-ETRN\r\n250-STARTTLS\r\n250-ENHANCEDSTATUSCODES\r\n250-8BITMIME\r\n250-DSN\r\n250-SMTPUTF8\r\n250 CHUNKING\r\n
2021/02/06 14:50:48 <- 250-receiver\r\n250-PIPELINING\r\n250-SIZE 10240000\r\n250-VRFY\r\n250-ETRN\r\n250-ENHANCEDSTATUSCODES\r\n250-8BITMIME\r\n250-DSN\r\n250-SMTPUTF8\r\n250 CHUNKING\r\n
2021/02/06 14:50:48 |> STARTTLS\r\n
2021/02/06 14:50:48 >| MAIL FROM:<root@sender> SIZE=327\r\nRCPT TO:<root@receiver> ORCPT=rfc822;root@receiver\r\nDATA\r\n
2021/02/06 14:50:48 |< 220 2.0.0 Ready to start TLS\r\n
2021/02/06 14:50:48 |> EHLO sender\r\n
2021/02/06 14:50:48 pipe locked for tls connection
2021/02/06 14:50:48 |< 250-receiver\r\n250-PIPELINING\r\n250-SIZE 10240000\r\n250-VRFY\r\n250-ETRN\r\n250-ENHANCEDSTATUSCODES\r\n250-8BITMIME\r\n250-DSN\r\n250-SMTPUTF8\r\n250 CHUNKING\r\n
2021/02/06 14:50:48 tls connected, to pipe unlocked
2021/02/06 14:50:48 -> MAIL FROM:<root@sender> SIZE=327\r\nRCPT TO:<root@receiver> ORCPT=rfc822;root@receiver\r\nDATA\r\n
2021/02/06 14:50:48 <- 250 2.1.0 Ok\r\n250 2.1.5 Ok\r\n354 End data with <CR><LF>.<CR><LF>\r\n
2021/02/06 14:50:48 -> Received: from sender (localhost [127.0.0.1])\r\n        by sender (Postfix) with SMTP id 45B113EA9B\r\n for <root@receiver>; Sat,  6 Feb 2021 14:50:48 +0000 (UTC)\r\nFrom: <root@sender>\r\nTo: <root@receiver>\r\nDate: Sat,  6 Feb 2021 14:50:48 +0000 (UTC)\r\nMessage-Id: <a77e.0003.0000@sender>\r\nSubject: Hi, Receiver from Sender\r\n\r\nXXXXXXXXXX\r\n.\r\nQUIT\r\n
2021/02/06 14:50:48 <- 250 2.0.0 Ok: queued as 76DAD4113D\r\n221 2.0.0 Bye\r\n
2021/02/06 14:50:48 connections closed

Received mail on receiver:

warp main 🏄 vagrant ssh receiver
vagrant@receiver:~$ sudo cat /var/spool/mail/root
From root@sender  Fri Feb  5 16:00:41 2021
Return-Path: <root@sender>
X-Original-To: root@receiver
Delivered-To: root@receiver
Received: from receiver (proxy [192.168.30.30])
        by receiver (Postfix) with ESMTPS id 3B9874160A
        for <root@receiver>; Fri,  5 Feb 2021 16:00:41 +0000 (UTC)
Received: from sender (localhost [127.0.0.1])
        by sender (Postfix) with SMTP id C08023E8E0
        for <root@receiver>; Fri,  5 Feb 2021 16:00:01 +0000 (UTC)
From: <root@sender>
To: <root@receiver>
Date: Fri,  5 Feb 2021 16:00:01 +0000 (UTC)
Message-Id: <c2f05.0003.0000@sender>
Subject: Hi, Receiver from Sender

XXXXXXXXXX

Plugins

Warp outputs logs as stdout, but plugins can save logs to a database or a specified file.

Native Plugins:

  • MySQL
    export DSN="warp:PASSWORD@tcp(localhost:3306)/warp"
    
  • SQLite
    export DSN="/var/db/warp.sqlite3"
    
  • File
    export FILE_PATH="/tmp/warp.log"
    
warp main 🏄 vagrant ssh sender
vagrant@sender:~$ cd /vagrant
vagrant@sender:/vagrant$ make plugin && make
env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=plugin -o .dist/mysql.so plugin/mysql/main.go
env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=plugin -o .dist/file.so plugin/file/main.go
env GOOS=linux GOARCH=amd64 go build -o warp ./cmd/warp/main.go
vagrant@sender:/vagrant$ /vagrant/warp -ip 192.168.30.30 -port 10025

Run on vagrant:

vagrant@sender:/vagrant$ sudo mysql -uroot -D warp
mysql> select * from connections;
+----------------------------+-------------+---------------+----------------------------+
| id                         | mail_from   | mail_to       | occurred_at                |
+----------------------------+-------------+---------------+----------------------------+
| 01FR74VW574PVQ5WGYE5RQATTG | root@sender | root@receiver | 2021-12-31 02:24:56.009302 |
| 01FR755XZKA594WA8SACQB4HC3 | root@sender | root@receiver | 2021-12-31 02:30:25.557302 |
+----------------------------+-------------+---------------+----------------------------+
2 rows in set (0.00 sec)

mysql> select communications.occurred_at, direction as d, substring(data, 1, 40) as data from communications, connections where connections.id = communications.connection_id and connections.id = "01FR755XZKA594WA8SACQB4HC3" order by communications.occurred_at;
+----------------------------+----+------------------------------------------+
| occurred_at                | d  | data                                     |
+----------------------------+----+------------------------------------------+
| 2021-12-31 02:30:25.523678 | -- | connected to 192.168.30.50:25            |
| 2021-12-31 02:30:25.534128 | <- | 220 receiver ESMTP Postfix (Ubuntu)\r\n  |
| 2021-12-31 02:30:25.534692 | -> | EHLO sender\r\n                          |
| 2021-12-31 02:30:25.535251 | <- | 250-receiver\r\n250-PIPELINING\r\n250-SI |
| 2021-12-31 02:30:25.535399 | |< | 250-receiver\r\n250-PIPELINING\r\n250-SI |
| 2021-12-31 02:30:25.538790 | -- | pipe locked for tls connection           |
| 2021-12-31 02:30:25.538791 | |> | STARTTLS\r\n                             |
| 2021-12-31 02:30:25.538820 | >| | MAIL FROM:<root@sender> SIZE=327\r\nRCPT |
| 2021-12-31 02:30:25.539568 | |< | 220 2.0.0 Ready to start TLS\r\n         |
| 2021-12-31 02:30:25.539701 | |> | EHLO sender\r\n                          |
| 2021-12-31 02:30:25.547124 | |< | 250-receiver\r\n250-PIPELINING\r\n250-SI |
| 2021-12-31 02:30:25.547459 | -- | tls connected, to pipe unlocked          |
| 2021-12-31 02:30:25.547811 | -> | MAIL FROM:<root@sender> SIZE=327\r\nRCPT |
| 2021-12-31 02:30:25.554912 | <- | 250 2.1.0 Ok\r\n250 2.1.5 Ok\r\n354 End  |
| 2021-12-31 02:30:25.555126 | -> | Received: from sender (localhost [127.0. |
| 2021-12-31 02:30:25.556812 | <- | 250 2.0.0 Ok: queued as 1EA19412C8\r\n22 |
| 2021-12-31 02:30:25.559877 | -- | connections closed                       |
+----------------------------+----+------------------------------------------+
17 rows in set (0.00 sec)

Author

linyows

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 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 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 HookFile added in v0.11.0

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

func (*HookFile) AfterComm added in v0.11.0

func (h *HookFile) AfterComm(d *AfterCommData)

func (*HookFile) AfterConn added in v0.11.0

func (h *HookFile) AfterConn(d *AfterConnData)

func (*HookFile) AfterInit added in v0.11.0

func (h *HookFile) AfterInit()

func (*HookFile) Name added in v0.11.0

func (h *HookFile) Name() string

type HookMysql added in v0.11.0

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

func (*HookMysql) AfterComm added in v0.11.0

func (h *HookMysql) AfterComm(d *AfterCommData)

func (*HookMysql) AfterConn added in v0.11.0

func (h *HookMysql) AfterConn(d *AfterConnData)

func (*HookMysql) AfterInit added in v0.11.0

func (h *HookMysql) AfterInit()

func (*HookMysql) Name added in v0.11.0

func (h *HookMysql) Name() string

type HookSqlite added in v0.11.0

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

func (*HookSqlite) AfterComm added in v0.11.0

func (h *HookSqlite) AfterComm(d *AfterCommData)

func (*HookSqlite) AfterConn added in v0.11.0

func (h *HookSqlite) AfterConn(d *AfterConnData)

func (*HookSqlite) AfterInit added in v0.11.0

func (h *HookSqlite) AfterInit()

func (*HookSqlite) Name added in v0.11.0

func (h *HookSqlite) Name() string

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 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
	// 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
	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
plugins

Jump to

Keyboard shortcuts

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