Created
July 26, 2016 02:30
-
-
Save tangnotes/061ecdab60d39fa342aee7fdbb9bdfa4 to your computer and use it in GitHub Desktop.
TCP Example of SMTP Authentication
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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