Skip to content

Instantly share code, notes, and snippets.

@tangnotes
Created July 26, 2016 02:30
Show Gist options
  • Save tangnotes/061ecdab60d39fa342aee7fdbb9bdfa4 to your computer and use it in GitHub Desktop.
Save tangnotes/061ecdab60d39fa342aee7fdbb9bdfa4 to your computer and use it in GitHub Desktop.
TCP Example of SMTP Authentication
// reference: https://tools.ietf.org/html/rfc5321
package main
import (
"bufio"
"encoding/base64"
"fmt"
"log"
"net"
"os"
"os/signal"
"strings"
"syscall"
)
func main() {
closed := make(chan struct{})
user := "USERNAME"
pass := "PASSWORD"
host := "SMTP_SERVER"
//port := "587"
port := "25"
conn, err := net.Dial("tcp", host+":"+port)
if err != nil {
log.Panic(err)
}
defer conn.Close()
go func() {
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
<-signals
log.Println("Initializing shutdown...")
close(closed)
}()
var code string
var message string
var more []string
code = printAndGetCode(conn)
fmt.Printf("code: %s\n", code)
conn.Write([]byte("EHLO " + host + "\r\n"))
code = printAndGetCode(conn)
//334 VXNlcm5hbWU6
//334 UGFzc3dvcmQ6
conn.Write([]byte("AUTH LOGIN\r\n"))
code, message, more = parseResp(conn)
printMoreMsg(more)
if code != "334" && message != "VXNlcm5hbWU6" {
log.Printf("Error(1): %s: %s\n", code, message)
}
conn.Write([]byte(base64.StdEncoding.EncodeToString([]byte(user)) + "\r\n"))
// Expected: 334 UGFzc3dvcmQ6
code, message, more = parseResp(conn)
printMoreMsg(more)
if code != "334" && message != "UGFzc3dvcmQ6" {
log.Printf("Error(2): %s: %s\n", code, message)
}
conn.Write([]byte(base64.StdEncoding.EncodeToString([]byte(pass)) + "\r\n"))
code, message, more = parseResp(conn)
if code != "235" && strings.Index(message, "Authentication successful") < 0 {
log.Printf("Error(3): %s: %s\n", code, message)
} else {
log.Printf("OK: %s#%s\n", code, message)
}
<-closed
fmt.Println("Done")
}
func readAndPrint(conn net.Conn) {
buf := make([]byte, 1024)
for {
l, err := conn.Read(buf)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("Len: %d\n", l)
if l > 0 {
fmt.Printf("Data: %s\n", string(buf[0:l]))
}
return
}
}
func parseResp(conn net.Conn) (code string, message string, more []string) {
count := 0
br := bufio.NewReader(conn)
for {
resp, _ := br.ReadString('\n')
if len(resp) > 4 {
code = resp[0:3]
if resp[3:4] == "-" {
more = append(more, strings.TrimSpace(resp))
} else {
message = strings.TrimSpace(resp[4:])
return
}
}
count++
if count > 20 {
fmt.Println("WARN: force break")
return
}
}
}
func printAndGetCode(conn net.Conn) string {
code, message, more := parseResp(conn)
if len(more) > 0 {
for _, m := range more {
fmt.Println(m)
}
}
fmt.Printf("%s %s", code, message)
return code
}
func printMoreMsg(more []string) {
if len(more) > 0 {
for _, m := range more {
fmt.Println(m)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment