Просмотр исходного кода

Misc. fixes and cleanups
* Dispersed constants to related source files.
* Have both types of I/O timeout on idle ActivityMonitoredConn.
* Use single client I/O timeout value for http.Server due to
WriteTimeout period; document issue.
* Explicitly use only read activity for GetActiveDuration; document
reason.
* In ActivityMonitoredConn, actually check Set[...]Deadline return
value (as it was failing, although not a problem in practice).
* meekConn.SetDeadline documents idle timeout situation and checks
that ActivityMonitoredConn functionality is accommodated.
* Explicitly prohibit port forwards to localhost and loopback (in case
this isn't handled by iptables or containerization).
* rejectNewChannel now returns minimal info to client.

Rod Hynes 9 лет назад
Родитель
Сommit
2ec729cd2a

+ 36 - 29
psiphon/net.go

@@ -741,7 +741,7 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
 // ActivityMonitoredConn wraps a net.Conn, adding logic to deal with
 // events triggered by I/O activity.
 //
-// When an inactivity timeout is specified, the net.Conn Read() will
+// When an inactivity timeout is specified, the network I/O will
 // timeout after the specified period of read inactivity. Optionally,
 // ActivityMonitoredConn will also consider the connection active when
 // data is written to it.
@@ -751,33 +751,36 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
 //
 type ActivityMonitoredConn struct {
 	net.Conn
-	inactivityTimeout time.Duration
-	activeOnWrite     bool
-	startTime         int64
-	lastActivityTime  int64
-	lruEntry          *LRUConnsEntry
+	inactivityTimeout    time.Duration
+	activeOnWrite        bool
+	startTime            int64
+	lastReadActivityTime int64
+	lruEntry             *LRUConnsEntry
 }
 
 func NewActivityMonitoredConn(
 	conn net.Conn,
 	inactivityTimeout time.Duration,
 	activeOnWrite bool,
-	lruEntry *LRUConnsEntry) *ActivityMonitoredConn {
+	lruEntry *LRUConnsEntry) (*ActivityMonitoredConn, error) {
 
 	if inactivityTimeout > 0 {
-		conn.SetReadDeadline(time.Now().Add(inactivityTimeout))
+		err := conn.SetDeadline(time.Now().Add(inactivityTimeout))
+		if err != nil {
+			return nil, ContextError(err)
+		}
 	}
 
 	now := time.Now().UnixNano()
 
 	return &ActivityMonitoredConn{
-		Conn:              conn,
-		inactivityTimeout: inactivityTimeout,
-		activeOnWrite:     activeOnWrite,
-		startTime:         now,
-		lastActivityTime:  now,
-		lruEntry:          lruEntry,
-	}
+		Conn:                 conn,
+		inactivityTimeout:    inactivityTimeout,
+		activeOnWrite:        activeOnWrite,
+		startTime:            now,
+		lastReadActivityTime: now,
+		lruEntry:             lruEntry,
+	}, nil
 }
 
 // GetStartTime gets the time when the ActivityMonitoredConn was
@@ -787,46 +790,50 @@ func (conn *ActivityMonitoredConn) GetStartTime() time.Time {
 }
 
 // GetActiveDuration returns the time elapsed between the initialization
-// of the ActivityMonitoredConn and the last Read (or Write when
-// activeOnWrite is specified).
+// of the ActivityMonitoredConn and the last Read. Only reads are used
+// for this calculation since writes may succeed locally due to buffering.
 func (conn *ActivityMonitoredConn) GetActiveDuration() time.Duration {
-	return time.Duration(atomic.LoadInt64(&conn.lastActivityTime) - conn.startTime)
+	return time.Duration(atomic.LoadInt64(&conn.lastReadActivityTime) - conn.startTime)
 }
 
 func (conn *ActivityMonitoredConn) Read(buffer []byte) (int, error) {
 	n, err := conn.Conn.Read(buffer)
 	if err == nil {
 
-		atomic.StoreInt64(&conn.lastActivityTime, time.Now().UnixNano())
-
 		if conn.inactivityTimeout > 0 {
-			conn.Conn.SetReadDeadline(time.Now().Add(conn.inactivityTimeout))
+			err = conn.Conn.SetDeadline(time.Now().Add(conn.inactivityTimeout))
+			if err != nil {
+				return n, ContextError(err)
+			}
 		}
-
 		if conn.lruEntry != nil {
 			conn.lruEntry.Touch()
 		}
+
+		atomic.StoreInt64(&conn.lastReadActivityTime, time.Now().UnixNano())
+
 	}
+	// Note: no context error to preserve error type
 	return n, err
 }
 
 func (conn *ActivityMonitoredConn) Write(buffer []byte) (int, error) {
 	n, err := conn.Conn.Write(buffer)
-	if err == nil {
-
-		if conn.activeOnWrite {
+	if err == nil && conn.activeOnWrite {
 
-			atomic.StoreInt64(&conn.lastActivityTime, time.Now().UnixNano())
-
-			if conn.inactivityTimeout > 0 {
-				conn.Conn.SetReadDeadline(time.Now().Add(conn.inactivityTimeout))
+		if conn.inactivityTimeout > 0 {
+			err = conn.Conn.SetDeadline(time.Now().Add(conn.inactivityTimeout))
+			if err != nil {
+				return n, ContextError(err)
 			}
 		}
 
 		if conn.lruEntry != nil {
 			conn.lruEntry.Touch()
 		}
+
 	}
+	// Note: no context error to preserve error type
 	return n, err
 }
 

+ 10 - 18
psiphon/server/config.go

@@ -31,7 +31,6 @@ import (
 	"net"
 	"strconv"
 	"strings"
-	"time"
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 	"golang.org/x/crypto/nacl/box"
@@ -39,23 +38,16 @@ import (
 )
 
 const (
-	SERVER_CONFIG_FILENAME                = "psiphond.config"
-	SERVER_TRAFFIC_RULES_FILENAME         = "psiphond-traffic-rules.config"
-	SERVER_ENTRY_FILENAME                 = "server-entry.dat"
-	DEFAULT_SERVER_IP_ADDRESS             = "127.0.0.1"
-	WEB_SERVER_SECRET_BYTE_LENGTH         = 32
-	DISCOVERY_VALUE_KEY_BYTE_LENGTH       = 32
-	WEB_SERVER_READ_TIMEOUT               = 10 * time.Second
-	WEB_SERVER_WRITE_TIMEOUT              = 10 * time.Second
-	SSH_USERNAME_SUFFIX_BYTE_LENGTH       = 8
-	SSH_PASSWORD_BYTE_LENGTH              = 32
-	SSH_RSA_HOST_KEY_BITS                 = 2048
-	SSH_HANDSHAKE_TIMEOUT                 = 30 * time.Second
-	SSH_CONNECTION_READ_DEADLINE          = 5 * time.Minute
-	SSH_TCP_PORT_FORWARD_DIAL_TIMEOUT     = 30 * time.Second
-	SSH_TCP_PORT_FORWARD_COPY_BUFFER_SIZE = 8192
-	SSH_OBFUSCATED_KEY_BYTE_LENGTH        = 32
-	GEOIP_SESSION_CACHE_TTL               = 60 * time.Minute
+	SERVER_CONFIG_FILENAME          = "psiphond.config"
+	SERVER_TRAFFIC_RULES_FILENAME   = "psiphond-traffic-rules.config"
+	SERVER_ENTRY_FILENAME           = "server-entry.dat"
+	DEFAULT_SERVER_IP_ADDRESS       = "127.0.0.1"
+	WEB_SERVER_SECRET_BYTE_LENGTH   = 32
+	DISCOVERY_VALUE_KEY_BYTE_LENGTH = 32
+	SSH_USERNAME_SUFFIX_BYTE_LENGTH = 8
+	SSH_PASSWORD_BYTE_LENGTH        = 32
+	SSH_RSA_HOST_KEY_BITS           = 2048
+	SSH_OBFUSCATED_KEY_BYTE_LENGTH  = 32
 )
 
 // Config specifies the configuration and behavior of a Psiphon

+ 8 - 5
psiphon/server/geoip.go

@@ -30,7 +30,10 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 )
 
-const UNKNOWN_GEOIP_VALUE = "None"
+const (
+	GEOIP_SESSION_CACHE_TTL = 60 * time.Minute
+	GEOIP_UNKNOWN_VALUE     = "None"
+)
 
 // GeoIPData is GeoIP data for a client session. Individual client
 // IP addresses are neither logged nor explicitly referenced during a session.
@@ -46,12 +49,12 @@ type GeoIPData struct {
 }
 
 // NewGeoIPData returns a GeoIPData initialized with the expected
-// UNKNOWN_GEOIP_VALUE values to be used when GeoIP lookup fails.
+// GEOIP_UNKNOWN_VALUE values to be used when GeoIP lookup fails.
 func NewGeoIPData() GeoIPData {
 	return GeoIPData{
-		Country: UNKNOWN_GEOIP_VALUE,
-		City:    UNKNOWN_GEOIP_VALUE,
-		ISP:     UNKNOWN_GEOIP_VALUE,
+		Country: GEOIP_UNKNOWN_VALUE,
+		City:    GEOIP_UNKNOWN_VALUE,
+		ISP:     GEOIP_UNKNOWN_VALUE,
 	}
 }
 

+ 41 - 22
psiphon/server/meek.go

@@ -44,25 +44,27 @@ import (
 //
 // https://bitbucket.org/psiphon/psiphon-circumvention-system/src/default/go/meek-client/meek-client.go
 
-// Protocol version 1 clients can handle arbitrary length response bodies. Older clients
-// report no version number and expect at most 64K response bodies.
-const MEEK_PROTOCOL_VERSION_1 = 1
-
-// Protocol version 2 clients initiate a session by sending a encrypted and obfuscated meek
-// cookie with their initial HTTP request. Connection information is contained within the
-// encrypted cookie payload. The server inspects the cookie and establishes a new session and
-// returns a new random session ID back to client via Set-Cookie header. The client uses this
-// session ID on all subsequent requests for the remainder of the session.
-const MEEK_PROTOCOL_VERSION_2 = 2
-
-const MEEK_MAX_PAYLOAD_LENGTH = 0x10000
-const MEEK_TURN_AROUND_TIMEOUT = 20 * time.Millisecond
-const MEEK_EXTENDED_TURN_AROUND_TIMEOUT = 100 * time.Millisecond
-const MEEK_MAX_SESSION_STALENESS = 45 * time.Second
-const MEEK_HTTP_CLIENT_READ_TIMEOUT = 45 * time.Second
-const MEEK_HTTP_CLIENT_WRITE_TIMEOUT = 10 * time.Second
-const MEEK_MIN_SESSION_ID_LENGTH = 8
-const MEEK_MAX_SESSION_ID_LENGTH = 20
+const (
+
+	// Protocol version 1 clients can handle arbitrary length response bodies. Older clients
+	// report no version number and expect at most 64K response bodies.
+	MEEK_PROTOCOL_VERSION_1 = 1
+
+	// Protocol version 2 clients initiate a session by sending a encrypted and obfuscated meek
+	// cookie with their initial HTTP request. Connection information is contained within the
+	// encrypted cookie payload. The server inspects the cookie and establishes a new session and
+	// returns a new random session ID back to client via Set-Cookie header. The client uses this
+	// session ID on all subsequent requests for the remainder of the session.
+	MEEK_PROTOCOL_VERSION_2 = 2
+
+	MEEK_MAX_PAYLOAD_LENGTH           = 0x10000
+	MEEK_TURN_AROUND_TIMEOUT          = 20 * time.Millisecond
+	MEEK_EXTENDED_TURN_AROUND_TIMEOUT = 100 * time.Millisecond
+	MEEK_MAX_SESSION_STALENESS        = 45 * time.Second
+	MEEK_HTTP_CLIENT_IO_TIMEOUT       = 45 * time.Second
+	MEEK_MIN_SESSION_ID_LENGTH        = 8
+	MEEK_MAX_SESSION_ID_LENGTH        = 20
+)
 
 // MeekServer implements the meek protocol, which tunnels TCP traffic (in the case of Psiphon,
 // Obfusated SSH traffic) over HTTP. Meek may be fronted (through a CDN) or direct and may be
@@ -144,9 +146,17 @@ func (server *MeekServer) Run() error {
 
 	// Serve HTTP or HTTPS
 
+	// Notes:
+	// - WriteTimeout may include time awaiting request, as per:
+	//   https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts
+	// - Legacy meek-server wrapped each client HTTP connection with an explict idle
+	//   timeout net.Conn and didn't use http.Server timeouts. We could do the same
+	//   here (use ActivityMonitoredConn) but the stock http.Server timeouts should
+	//   now be sufficient.
+
 	httpServer := &http.Server{
-		ReadTimeout:  MEEK_HTTP_CLIENT_READ_TIMEOUT,
-		WriteTimeout: MEEK_HTTP_CLIENT_WRITE_TIMEOUT,
+		ReadTimeout:  MEEK_HTTP_CLIENT_IO_TIMEOUT,
+		WriteTimeout: MEEK_HTTP_CLIENT_IO_TIMEOUT,
 		Handler:      server,
 		ConnState:    server.httpConnStateCallback,
 
@@ -764,8 +774,17 @@ func (conn *meekConn) RemoteAddr() net.Addr {
 	return conn.remoteAddr
 }
 
-// Stub implementation of net.Conn.SetDeadline
+// SetDeadline is not a true implementation of net.Conn.SetDeadline. It
+// merely checks that the requested timeout exceeds the MEEK_MAX_SESSION_STALENESS
+// period. When it does, and the session is idle, the meekConn Read/Write will
+// be interrupted and return io.EOF (not a timeout error) before the deadline.
+// In other words, this conn will approximate the desired functionality of
+// timing out on idle on or before the requested deadline.
 func (conn *meekConn) SetDeadline(t time.Time) error {
+	// Overhead: nanoseconds (https://blog.cloudflare.com/its-go-time-on-linux/)
+	if time.Now().Add(MEEK_MAX_SESSION_STALENESS).Before(t) {
+		return nil
+	}
 	return psiphon.ContextError(errors.New("not supported"))
 }
 

+ 6 - 1
psiphon/server/server_test.go

@@ -109,9 +109,14 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 
 	// create a server
 
+	serverIPaddress, err := psiphon.GetInterfaceIPAddress("en0")
+	if err != nil {
+		t.Fatalf("error getting server IP address: %s", err)
+	}
+
 	serverConfigJSON, _, encodedServerEntry, err := GenerateConfig(
 		&GenerateConfigParams{
-			ServerIPAddress:      "127.0.0.1",
+			ServerIPAddress:      serverIPaddress,
 			EnableSSHAPIRequests: runConfig.enableSSHAPIRequests,
 			WebServerPort:        8000,
 			TunnelProtocolPorts:  map[string]int{runConfig.tunnelProtocol: 4000},

+ 51 - 21
psiphon/server/tunnelServer.go

@@ -34,6 +34,18 @@ import (
 	"golang.org/x/crypto/ssh"
 )
 
+const (
+	SSH_HANDSHAKE_TIMEOUT                 = 30 * time.Second
+	SSH_CONNECTION_READ_DEADLINE          = 5 * time.Minute
+	SSH_TCP_PORT_FORWARD_DIAL_TIMEOUT     = 30 * time.Second
+	SSH_TCP_PORT_FORWARD_COPY_BUFFER_SIZE = 8192
+)
+
+// Disallowed port forward hosts is a failsafe. The server should
+// be run on a host with correctly configured firewall rules, or
+// containerization, or both.
+var SSH_DISALLOWED_PORT_FORWARD_HOSTS = []string{"localhost", "127.0.0.1"}
+
 // TunnelServer is the main server that accepts Psiphon client
 // connections, via various obfuscation protocols, and provides
 // port forwarding (TCP and UDP) services to the Psiphon client.
@@ -408,13 +420,19 @@ func (sshServer *sshServer) handleClient(tunnelProtocol string, clientConn net.C
 	// terminate the connection if no data is received before the deadline. This
 	// timeout is in effect for the entire duration of the SSH connection. Clients
 	// must actively use the connection or send SSH keep alive requests to keep
-	// the connection active.
+	// the connection active. Writes are not considered reliable activity indicators
+	// due to buffering.
 
-	activityConn := psiphon.NewActivityMonitoredConn(
+	activityConn, err := psiphon.NewActivityMonitoredConn(
 		clientConn,
 		SSH_CONNECTION_READ_DEADLINE,
 		false,
 		nil)
+	if err != nil {
+		clientConn.Close()
+		log.WithContextFields(LogFields{"error": err}).Error("NewActivityMonitoredConn failed")
+		return
+	}
 	clientConn = activityConn
 
 	// Further wrap the connection in a rate limiting ThrottledConn.
@@ -741,15 +759,15 @@ func (sshClient *sshClient) runClient(
 	requestsWaitGroup.Wait()
 }
 
-func (sshClient *sshClient) rejectNewChannel(newChannel ssh.NewChannel, reason ssh.RejectionReason, message string) {
-	// TODO: log more details?
+func (sshClient *sshClient) rejectNewChannel(newChannel ssh.NewChannel, reason ssh.RejectionReason, logMessage string) {
 	log.WithContextFields(
 		LogFields{
-			"channelType":   newChannel.ChannelType(),
-			"rejectMessage": message,
-			"rejectReason":  reason,
+			"channelType":  newChannel.ChannelType(),
+			"logMessage":   logMessage,
+			"rejectReason": reason.String(),
 		}).Warning("reject new channel")
-	newChannel.Reject(reason, message)
+	// Note: logMessage is internal, for logging only; just the RejectionReason is sent to the client
+	newChannel.Reject(reason, reason.String())
 }
 
 func (sshClient *sshClient) handleNewPortForwardChannel(newChannel ssh.NewChannel) {
@@ -786,7 +804,11 @@ func (sshClient *sshClient) handleNewPortForwardChannel(newChannel ssh.NewChanne
 }
 
 func (sshClient *sshClient) isPortForwardPermitted(
-	port int, allowPorts []int, denyPorts []int) bool {
+	host string, port int, allowPorts []int, denyPorts []int) bool {
+
+	if psiphon.Contains(SSH_DISALLOWED_PORT_FORWARD_HOSTS, host) {
+		return false
+	}
 
 	// TODO: faster lookup?
 	if len(allowPorts) > 0 {
@@ -797,6 +819,7 @@ func (sshClient *sshClient) isPortForwardPermitted(
 		}
 		return false
 	}
+
 	if len(denyPorts) > 0 {
 		for _, denyPort := range denyPorts {
 			if port == denyPort {
@@ -804,6 +827,7 @@ func (sshClient *sshClient) isPortForwardPermitted(
 			}
 		}
 	}
+
 	return true
 }
 
@@ -847,6 +871,7 @@ func (sshClient *sshClient) handleTCPChannel(
 	newChannel ssh.NewChannel) {
 
 	if !sshClient.isPortForwardPermitted(
+		hostToConnect,
 		portToConnect,
 		sshClient.trafficRules.AllowTCPPorts,
 		sshClient.trafficRules.DenyTCPPorts) {
@@ -950,31 +975,36 @@ func (sshClient *sshClient) handleTCPChannel(
 	fwdConn := result.conn
 	defer fwdConn.Close()
 
-	lruEntry := sshClient.tcpPortForwardLRU.Add(fwdConn)
-	defer lruEntry.Remove()
+	fwdChannel, requests, err := newChannel.Accept()
+	if err != nil {
+		log.WithContextFields(LogFields{"error": err}).Warning("accept new channel failed")
+		return
+	}
+	go ssh.DiscardRequests(requests)
+	defer fwdChannel.Close()
 
 	// ActivityMonitoredConn monitors the TCP port forward I/O and updates
-	// its LRU status. ActivityMonitoredConn also times out read on the port
+	// its LRU status. ActivityMonitoredConn also times out I/O on the port
 	// forward if both reads and writes have been idle for the specified
 	// duration.
-	fwdConn = psiphon.NewActivityMonitoredConn(
+
+	lruEntry := sshClient.tcpPortForwardLRU.Add(fwdConn)
+	defer lruEntry.Remove()
+
+	fwdConn, err = psiphon.NewActivityMonitoredConn(
 		fwdConn,
 		time.Duration(sshClient.trafficRules.IdleTCPPortForwardTimeoutMilliseconds)*time.Millisecond,
 		true,
 		lruEntry)
-
-	fwdChannel, requests, err := newChannel.Accept()
-	if err != nil {
-		log.WithContextFields(LogFields{"error": err}).Warning("accept new channel failed")
+	if result.err != nil {
+		log.WithContextFields(LogFields{"error": err}).Error("NewActivityMonitoredConn failed")
 		return
 	}
-	go ssh.DiscardRequests(requests)
-	defer fwdChannel.Close()
-
-	log.WithContextFields(LogFields{"remoteAddr": remoteAddr}).Debug("relaying")
 
 	// Relay channel to forwarded connection.
 
+	log.WithContextFields(LogFields{"remoteAddr": remoteAddr}).Debug("relaying")
+
 	// TODO: relay errors to fwdChannel.Stderr()?
 	relayWaitGroup := new(sync.WaitGroup)
 	relayWaitGroup.Add(1)

+ 21 - 13
psiphon/server/udp.go

@@ -140,7 +140,17 @@ func (mux *udpPortForwardMultiplexer) run() {
 
 			// Create a new port forward
 
+			dialIP := net.IP(message.remoteIP)
+			dialPort := int(message.remotePort)
+
+			// Transparent DNS forwarding
+			if message.forwardDNS {
+				dialIP = mux.sshClient.sshServer.support.DNSResolver.Get()
+				dialPort = DNS_RESOLVER_PORT
+			}
+
 			if !mux.sshClient.isPortForwardPermitted(
+				dialIP.String(),
 				int(message.remotePort),
 				mux.sshClient.trafficRules.AllowUDPPorts,
 				mux.sshClient.trafficRules.DenyUDPPorts) {
@@ -172,15 +182,6 @@ func (mux *udpPortForwardMultiplexer) run() {
 					}).Debug("closed LRU UDP port forward")
 			}
 
-			dialIP := net.IP(message.remoteIP)
-			dialPort := int(message.remotePort)
-
-			// Transparent DNS forwarding
-			if message.forwardDNS {
-				dialIP = mux.sshClient.sshServer.support.DNSResolver.Get()
-				dialPort = DNS_RESOLVER_PORT
-			}
-
 			log.WithContextFields(
 				LogFields{
 					"remoteAddr": fmt.Sprintf("%s:%d", dialIP.String(), dialPort),
@@ -195,17 +196,24 @@ func (mux *udpPortForwardMultiplexer) run() {
 				continue
 			}
 
-			lruEntry := mux.portForwardLRU.Add(udpConn)
-
 			// ActivityMonitoredConn monitors the TCP port forward I/O and updates
-			// its LRU status. ActivityMonitoredConn also times out read on the port
+			// its LRU status. ActivityMonitoredConn also times out I/O on the port
 			// forward if both reads and writes have been idle for the specified
 			// duration.
-			conn := psiphon.NewActivityMonitoredConn(
+
+			lruEntry := mux.portForwardLRU.Add(udpConn)
+
+			conn, err := psiphon.NewActivityMonitoredConn(
 				udpConn,
 				time.Duration(mux.sshClient.trafficRules.IdleUDPPortForwardTimeoutMilliseconds)*time.Millisecond,
 				true,
 				lruEntry)
+			if err != nil {
+				lruEntry.Remove()
+				mux.sshClient.closedPortForward(mux.sshClient.udpTrafficState, 0, 0)
+				log.WithContextFields(LogFields{"error": err}).Error("NewActivityMonitoredConn failed")
+				continue
+			}
 
 			portForward = &udpPortForward{
 				connID:       message.connID,

+ 8 - 2
psiphon/server/webServer.go

@@ -28,10 +28,13 @@ import (
 	"net"
 	"net/http"
 	"sync"
+	"time"
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 )
 
+const WEB_SERVER_IO_TIMEOUT = 10 * time.Second
+
 type webServer struct {
 	support  *SupportServices
 	serveMux *http.ServeMux
@@ -80,13 +83,16 @@ func RunWebServer(
 	logWriter := NewLogWriter()
 	defer logWriter.Close()
 
+	// Note: WriteTimeout includes time awaiting request, as per:
+	// https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts
+
 	server := &psiphon.HTTPSServer{
 		http.Server{
 			MaxHeaderBytes: MAX_API_PARAMS_SIZE,
 			Handler:        serveMux,
 			TLSConfig:      tlsConfig,
-			ReadTimeout:    WEB_SERVER_READ_TIMEOUT,
-			WriteTimeout:   WEB_SERVER_WRITE_TIMEOUT,
+			ReadTimeout:    WEB_SERVER_IO_TIMEOUT,
+			WriteTimeout:   WEB_SERVER_IO_TIMEOUT,
 			ErrorLog:       golanglog.New(logWriter, "", 0),
 		},
 	}