package main import ( "crypto/tls" "fmt" "io" "log" "net" "net/smtp" "os" "regexp" "strings" "time" "github.com/chrj/smtpd" ) func connectionChecker(peer smtpd.Peer) error { var peerIP net.IP if addr, ok := peer.Addr.(*net.TCPAddr); ok { peerIP = net.ParseIP(addr.IP.String()) } else { return smtpd.Error{Code: 421, Message: "Denied"} } nets := strings.Split(*allowedNets, " ") for i := range(nets) { _, allowedNet, _ := net.ParseCIDR(nets[i]) if allowedNet.Contains(peerIP) { return nil } } return smtpd.Error{Code: 421, Message: "Denied"} } func senderChecker(peer smtpd.Peer, addr string) error { // check sender address from auth file if user is authenticated if *allowedUsers != "" && peer.Username != "" { _, email, err := AuthFetch(peer.Username) if err != nil { return smtpd.Error{Code: 451, Message: "Bad sender address"} } if strings.ToLower(addr) != strings.ToLower(email) { return smtpd.Error{Code: 451, Message: "Bad sender address"} } } if *allowedSender == "" { return nil } re, err := regexp.Compile(*allowedSender) if err != nil { log.Printf("allowed_sender invalid: %v\n", err) return smtpd.Error{Code: 451, Message: "Bad sender address"} } if re.MatchString(addr) { return nil } return smtpd.Error{Code: 451, Message: "Bad sender address"} } func recipientChecker(peer smtpd.Peer, addr string) error { if *allowedRecipients == "" { return nil } re, err := regexp.Compile(*allowedRecipients) if err != nil { log.Printf("allowed_recipients invalid: %v\n", err) return smtpd.Error{Code: 451, Message: "Bad recipient address"} } if re.MatchString(addr) { return nil } return smtpd.Error{Code: 451, Message: "Bad recipient address"} } func authChecker(peer smtpd.Peer, username string, password string) error { err := AuthCheckPassword(username, password) if err != nil { log.Printf("Auth error: %v\n", err) return smtpd.Error{Code: 535, Message: "Authentication credentials invalid"} } return nil } func mailHandler(peer smtpd.Peer, env smtpd.Envelope) error { if *allowedUsers != "" && peer.Username == "" { return smtpd.Error{Code: 530, Message: "Authentication Required"} } peerIP := "" if addr, ok := peer.Addr.(*net.TCPAddr); ok { peerIP = addr.IP.String() } log.Printf("new mail from=<%s> to=%s peer=[%s]\n", env.Sender, env.Recipients, peerIP) var auth smtp.Auth host, _, _ := net.SplitHostPort(*remoteHost) if *remoteUser != "" && *remotePass != "" { auth = smtp.PlainAuth("", *remoteUser, *remotePass, host) } env.AddReceivedLine(peer) log.Printf("delivering using smarthost %s\n", *remoteHost) err := SendMail( *remoteHost, auth, env.Sender, env.Recipients, env.Data, ) if err != nil { log.Printf("delivery failed: %v\n", err); return smtpd.Error{Code: 554, Message: "Forwarding failed"} } log.Printf("%s delivery successful\n", env.Recipients) return nil } func main() { ConfigLoad() if *versionInfo { fmt.Printf("smtprelay/%s\n", VERSION) os.Exit(0) } if *logFile != "" { f, err := os.OpenFile(*logFile, os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0600) if err != nil { log.Fatalf("Error opening logfile: %v", err) } defer f.Close() log.SetOutput(io.MultiWriter(os.Stdout, f)) } listeners := strings.Split(*listen, " ") for i := range(listeners) { listener := listeners[i] server := &smtpd.Server{ Hostname: *hostName, WelcomeMessage: *welcomeMsg, ConnectionChecker: connectionChecker, SenderChecker: senderChecker, RecipientChecker: recipientChecker, Handler: mailHandler, } if *allowedUsers != "" { err := AuthLoadFile(*allowedUsers) if err != nil { log.Fatalf("Authentication file: %s\n", err) } server.Authenticator = authChecker } if strings.Index(listeners[i], "://") == -1 { log.Printf("Listen on %s ...\n", listener) go server.ListenAndServe(listener) } else if strings.HasPrefix(listeners[i], "starttls://") { listener = strings.TrimPrefix(listener, "starttls://") if *localCert == "" || *localKey == "" { log.Fatal("TLS certificate/key not defined in config") } cert, err := tls.LoadX509KeyPair(*localCert, *localKey) if err != nil { log.Fatal(err) } server.TLSConfig = &tls.Config { Certificates: [] tls.Certificate{cert}, } server.ForceTLS = *localForceTLS log.Printf("Listen on %s (STARTSSL) ...\n", listener) lsnr, err := net.Listen("tcp", listener) defer lsnr.Close() go server.Serve(lsnr) } else if strings.HasPrefix(listeners[i], "tls://") { listener = strings.TrimPrefix(listener, "tls://") if *localCert == "" || *localKey == "" { log.Fatal("TLS certificate/key not defined in config") } cert, err := tls.LoadX509KeyPair(*localCert, *localKey) if err != nil { log.Fatal(err) } server.TLSConfig = &tls.Config { Certificates: [] tls.Certificate{cert}, } log.Printf("Listen on %s (TLS) ...\n", listener) lsnr, err := tls.Listen("tcp", listener, server.TLSConfig) defer lsnr.Close() go server.Serve(lsnr) } else { log.Fatal("Unknown protocol in listener ", listener) } } for true { time.Sleep(time.Minute) } }