From 2e4d5eae8acb6916307529160b2efdb213726912 Mon Sep 17 00:00:00 2001 From: Jan Philipp Timme Date: Sun, 12 May 2019 19:05:56 +0200 Subject: [PATCH] Introduce a basic logger and some code for testing --- README.md | 11 +++++ logger.go | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 42 +++++++++++++++++ socket.go | 28 +++++++++++ 4 files changed, 218 insertions(+) create mode 100644 README.md create mode 100644 logger.go create mode 100644 main.go create mode 100644 socket.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..80a01fd --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Milter experiment + +This project is for educational purposes. +Any attempts to run this in production WILL FAIL! +Use this code as inspiration, but do not blame me for your losses. + + +# References + +* [The source code of sendmail-jilter](https://sourceforge.net/projects/sendmail-jilter/) +* [The Sendmail source code](https://ftp.sendmail.org/) diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..caa77df --- /dev/null +++ b/logger.go @@ -0,0 +1,137 @@ +package main + +import ( + "io" + "log" +) + +// Loglevel is used to set the current loglevel of Logger. +type Loglevel int + +const ( + // NONE is a loglevel for Logger. + NONE Loglevel = 0 + // ERROR is a loglevel for Logger. + ERROR Loglevel = 1 + // WARN is a loglevel for Logger. + WARN Loglevel = 2 + // INFO is a loglevel for Logger. + INFO Loglevel = 3 + // DEBUG is a loglevel for Logger. + DEBUG Loglevel = 4 +) + +// Logger uses multiple instances of log.Logger to provide logging methods for multiple loglevels. +type Logger struct { + debug *log.Logger + info *log.Logger + warn *log.Logger + error *log.Logger + logDebug bool + logInfo bool + logWarn bool + logError bool +} + +// NewLogger prepares a new instance of Logger for custom use. +func NewLogger(stdOut io.Writer, stdErr io.Writer, logLevel Loglevel) Logger { + newLogger := Logger{} + newLogger.debug = log.New(stdOut, "DEBUG ", 0) + newLogger.info = log.New(stdOut, "INFO ", 0) + newLogger.warn = log.New(stdErr, "WARN ", 0) + newLogger.error = log.New(stdErr, "ERROR ", 0) + newLogger.SetLogLevel(logLevel) + return newLogger +} + +// SetLogLevel can be used to change the loglevel of Logger on the fly. +func (l *Logger) SetLogLevel(logLevel Loglevel) { + l.logDebug = (logLevel >= DEBUG) + l.logInfo = (logLevel >= INFO) + l.logWarn = (logLevel >= WARN) + l.logError = (logLevel >= ERROR) +} + +// Debug is an alias for log.Logger.Print() with severity DEBUG. +func (l *Logger) Debug(v ...interface{}) { + if l.logDebug { + l.debug.Print(v...) + } +} + +// Debugln is an alias for log.Logger.Println() with severity DEBUG. +func (l *Logger) Debugln(v ...interface{}) { + if l.logDebug { + l.debug.Println(v...) + } +} + +// Debugf is an alias for log.Logger.Printf() with severity DEBUG. +func (l *Logger) Debugf(format string, v ...interface{}) { + if l.logDebug { + l.debug.Printf(format, v...) + } +} + +// Info is an alias for log.Logger.Print() with severity INFO. +func (l *Logger) Info(v ...interface{}) { + if l.logInfo { + l.info.Print(v...) + } +} + +// Infoln is an alias for log.Logger.Println() with severity INFO. +func (l *Logger) Infoln(v ...interface{}) { + if l.logInfo { + l.info.Println(v...) + } +} + +// Infof is an alias for log.Logger.Printf() with severity INFO. +func (l *Logger) Infof(format string, v ...interface{}) { + if l.logInfo { + l.info.Printf(format, v...) + } +} + +// Warn is an alias for log.Logger.Print() with severity WARN. +func (l *Logger) Warn(v ...interface{}) { + if l.logWarn { + l.warn.Print(v...) + } +} + +// Warnln is an alias for log.Logger.Println() with severity WARN. +func (l *Logger) Warnln(v ...interface{}) { + if l.logWarn { + l.warn.Println(v...) + } +} + +// Warnf is an alias for log.Logger.Printf() with severity WARN. +func (l *Logger) Warnf(format string, v ...interface{}) { + if l.logWarn { + l.warn.Printf(format, v...) + } +} + +// Error is an alias for log.Logger.Print() with severity ERROR. +func (l *Logger) Error(v ...interface{}) { + if l.logError { + l.error.Print(v...) + } +} + +// Errorln is an alias for log.Logger.Println() with severity ERROR. +func (l *Logger) Errorln(v ...interface{}) { + if l.logError { + l.error.Println(v...) + } +} + +// Errorf is an alias for log.Logger.Printf() with severity ERROR. +func (l *Logger) Errorf(format string, v ...interface{}) { + if l.logError { + l.error.Printf(format, v...) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a4e2d19 --- /dev/null +++ b/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "bufio" + "bytes" + "encoding/binary" + "encoding/hex" + "os" +) + +var ( + logger Logger +) + +func handleMtaConnection(clientConnection *bufio.ReadWriter) { + buf := make([]byte, 4096) + for { + bytesRead, err := clientConnection.Read(buf) + if err != nil { + logger.Errorln("Error reading from clientConnection:", err.Error()) + break + } else { + logger.Infof("Read %d bytes from connection\n", bytesRead) + logger.Debugf("%s", hex.Dump(buf[0:bytesRead])) + + // First 4 Bytes will be some integer thing "length" + // Let's parse that + var packetLength uint32 + bytesReader := bytes.NewReader(buf[0:4]) + err := binary.Read(bytesReader, binary.BigEndian, &packetLength) + if err != nil { + logger.Errorln(err.Error()) + } + logger.Debugf("Parsed length: %d\n", packetLength) + } + } +} + +func main() { + logger = NewLogger(os.Stdout, os.Stderr, DEBUG) + runServer() +} diff --git a/socket.go b/socket.go new file mode 100644 index 0000000..457bf82 --- /dev/null +++ b/socket.go @@ -0,0 +1,28 @@ +package main + +import ( + "bufio" + "net" + "os" +) + +func runServer() { + serverSocket, err := net.Listen("tcp", "127.0.0.1:7777") + if err != nil { + logger.Errorf("Could not create listening socket: %s\n", err.Error()) + os.Exit(1) + } else { + logger.Infof("Now listening for incoming connections.\n") + defer serverSocket.Close() + } + for { + clientConnection, err := serverSocket.Accept() + if err != nil { + logger.Warnf("Could not accept client connection: %s\n", err.Error()) + } else { + logger.Infof("Accepted client connection.\n") + milterReadWriter := bufio.NewReadWriter(bufio.NewReader(clientConnection), bufio.NewWriter(clientConnection)) + go handleMtaConnection(milterReadWriter) + } + } +}