Browse Source

fix issue #30 (#74)

Fixes #30 
- adds XCLIENT command
- adds new xclient_on bool option to server config
Flashmob 8 years ago
parent
commit
0b7bdbd873
3 changed files with 72 additions and 0 deletions
  1. 3 0
      config.go
  2. 18 0
      server.go
  3. 51 0
      server_test.go

+ 3 - 0
config.go

@@ -61,6 +61,9 @@ type ServerConfig struct {
 	// LogFile is where the logs go. Use path to file, or "stderr", "stdout" or "off".
 	// defaults to AppConfig.Log file setting
 	LogFile string `json:"log_file,omitempty"`
+	// XClientOn when using a proxy such as Nginx, XCLIENT command is used to pass the
+	// original client's IP address & client's HELO
+	XClientOn bool `json:"xclient_on,omitempty"`
 
 	// The following used to watch certificate changes so that the TLS can be reloaded
 	_privateKeyFile_mtime int

+ 18 - 0
server.go

@@ -369,6 +369,24 @@ func (server *server) handleClient(client *client) {
 				quote := response.GetQuote()
 				client.sendResponse("214-OK\r\n" + quote)
 
+			case sc.XClientOn && strings.Index(cmd, "XCLIENT ") == 0:
+				if toks := strings.Split(input[8:], " "); len(toks) > 0 {
+					for i := range toks {
+						if vals := strings.Split(toks[i], "="); len(vals) == 2 {
+							if vals[1] == "[UNAVAILABLE]" {
+								// skip
+								continue
+							}
+							if vals[0] == "ADDR" {
+								client.RemoteIP = vals[1]
+							}
+							if vals[0] == "HELO" {
+								client.Helo = vals[1]
+							}
+						}
+					}
+				}
+				client.sendResponse(response.Canned.SuccessMailCmd)
 			case strings.Index(cmd, "MAIL FROM:") == 0:
 				if client.isInTransaction() {
 					client.sendResponse(response.Canned.FailNestedMailCmd)

+ 51 - 0
server_test.go

@@ -93,5 +93,56 @@ func TestHandleClient(t *testing.T) {
 	wg.Wait() // wait for handleClient to exit
 }
 
+func TestXClient(t *testing.T) {
+	var mainlog log.Logger
+	var logOpenError error
+	sc := getMockServerConfig()
+	sc.XClientOn = true
+	mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
+	if logOpenError != nil {
+		mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
+	}
+	conn, server := getMockServerConn(sc, t)
+	// call the serve.handleClient() func in a goroutine.
+	client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		server.handleClient(client)
+		wg.Done()
+	}()
+	// Wait for the greeting from the server
+	r := textproto.NewReader(bufio.NewReader(conn.Client))
+	line, _ := r.ReadLine()
+	//	fmt.Println(line)
+	w := textproto.NewWriter(bufio.NewWriter(conn.Client))
+	w.PrintfLine("HELO test.test.com")
+	line, _ = r.ReadLine()
+	//fmt.Println(line)
+	w.PrintfLine("XCLIENT ADDR=212.96.64.216 NAME=[UNAVAILABLE]")
+	line, _ = r.ReadLine()
+
+	if client.RemoteIP != "212.96.64.216" {
+		t.Error("client.RemoteIP should be 212.96.64.216, but got:", client.RemoteIP)
+	}
+	expected := "250 2.1.0 OK"
+	if strings.Index(line, expected) != 0 {
+		t.Error("expected", expected, "but got:", line)
+	}
+
+	// try malformed input
+	w.PrintfLine("XCLIENT c")
+	line, _ = r.ReadLine()
+
+	expected = "250 2.1.0 OK"
+	if strings.Index(line, expected) != 0 {
+		t.Error("expected", expected, "but got:", line)
+	}
+
+	w.PrintfLine("QUIT")
+	line, _ = r.ReadLine()
+	wg.Wait() // wait for handleClient to exit
+}
+
 // TODO
 // - test github issue #44 and #42