diff --git a/irc/client.go b/irc/client.go index 15a3a383..60762429 100644 --- a/irc/client.go +++ b/irc/client.go @@ -66,6 +66,7 @@ type Client struct { nickMaskCasefolded string nickMaskString string // cache for nickmask string since it's used with lots of replies operName string + proxiedIP string // actual remote IP if using the PROXY protocol quitMessageSent bool quitMutex sync.Mutex quitTimer *time.Timer @@ -147,11 +148,19 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client { // IP returns the IP address of this client. func (client *Client) IP() net.IP { + if client.proxiedIP != "" { + return net.ParseIP(client.proxiedIP) + } + return net.ParseIP(IPString(client.socket.conn.RemoteAddr())) } // IPString returns the IP address of this client as a string. func (client *Client) IPString() string { + if client.proxiedIP != "" { + return client.proxiedIP + } + ip := client.IP().String() if 0 < len(ip) && ip[0] == ':' { ip = "0" + ip @@ -185,6 +194,7 @@ func (client *Client) run() { var msg ircmsg.IrcMessage // Set the hostname for this client + // (may be overridden by a later PROXY command from stunnel) client.rawHostname = AddrLookupHostname(client.socket.conn.RemoteAddr()) for { diff --git a/irc/commands.go b/irc/commands.go index 5bf80abd..c20e7b61 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -207,6 +207,11 @@ var Commands = map[string]Command{ handler: privmsgHandler, minParams: 2, }, + "PROXY": { + handler: proxyHandler, + usablePreReg: true, + minParams: 5, + }, "RENAME": { handler: renameHandler, minParams: 2, diff --git a/irc/config.go b/irc/config.go index 1c00bb11..f88ebcc4 100644 --- a/irc/config.go +++ b/irc/config.go @@ -202,7 +202,8 @@ type Config struct { RestAPI RestAPIConfig `yaml:"rest-api"` CheckIdent bool `yaml:"check-ident"` MOTD string - MaxSendQString string `yaml:"max-sendq"` + ProxyAllowedFrom []string `yaml:"proxy-allowed-from"` + MaxSendQString string `yaml:"max-sendq"` MaxSendQBytes uint64 ConnectionLimits ConnectionLimitsConfig `yaml:"connection-limits"` ConnectionThrottle ConnectionThrottleConfig `yaml:"connection-throttling"` diff --git a/irc/help.go b/irc/help.go index 9208fbf2..499fd830 100644 --- a/irc/help.go +++ b/irc/help.go @@ -356,6 +356,13 @@ Replies to a PING. Used to check link connectivity.`, text: `PRIVMSG {,} Sends the text to the given targets as a PRIVMSG.`, + }, + "proxy": { + oper: true, // not really, but it's restricted anyways + text: `PROXY TCP4/6 + +Used by haproxy's PROXY protocol, to allow for alternate TLS support: +http://www.haproxy.org/download/1.7/doc/proxy-protocol.txt`, }, "rename": { text: `RENAME [] diff --git a/irc/server.go b/irc/server.go index 532d8d7b..b969b2b9 100644 --- a/irc/server.go +++ b/irc/server.go @@ -109,6 +109,7 @@ type Server struct { rehashMutex sync.Mutex rehashSignal chan os.Signal restAPI *RestAPIConfig + proxyAllowedFrom []string signals chan os.Signal snomasks *SnoManager store *buntdb.DB @@ -217,6 +218,7 @@ func NewServer(configFilename string, config *Config, logger *logger.Manager) (* newConns: make(chan clientConn), operators: opers, operclasses: *operClasses, + proxyAllowedFrom: config.Server.ProxyAllowedFrom, registeredChannels: make(map[string]*RegisteredChannel), rehashSignal: make(chan os.Signal, 1), restAPI: &config.Server.RestAPI, @@ -2224,3 +2226,19 @@ func userhostHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool return false } + +// PROXY TCP4/6 SOURCEIP DESTIP SOURCEPORT DESTPORT +// http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt +func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { + clientAddress := IPString(client.socket.conn.RemoteAddr()) + clientHostname := client.hostname + for _, address := range server.proxyAllowedFrom { + if clientHostname == address || clientAddress == address { + client.proxiedIP = msg.Params[1] + client.hostname = LookupHostname(msg.Params[1]) + return false + } + } + client.Quit("PROXY command is not usable from your address") + return true +} diff --git a/oragono.yaml b/oragono.yaml index a215095a..5159df7a 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -65,6 +65,10 @@ server: # if you change the motd, you should move it to ircd.motd motd: oragono.motd + # addresses/hostnames the PROXY command can be used from + # this should be restricted to 127.0.0.1 and localhost at most + proxy-allowed-from: [] + # maximum length of clients' sendQ in bytes # this should be big enough to hold /LIST and HELP replies max-sendq: 16k