mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 20:09:41 +01:00
Allow WEBIRC from specified hosts
This commit is contained in:
parent
0cc5e68e0f
commit
34987ba53a
@ -276,6 +276,11 @@ var Commands = map[string]Command{
|
|||||||
handler: versionHandler,
|
handler: versionHandler,
|
||||||
minParams: 0,
|
minParams: 0,
|
||||||
},
|
},
|
||||||
|
"WEBIRC": {
|
||||||
|
handler: webircHandler,
|
||||||
|
usablePreReg: true,
|
||||||
|
minParams: 4,
|
||||||
|
},
|
||||||
"WHO": {
|
"WHO": {
|
||||||
handler: whoHandler,
|
handler: whoHandler,
|
||||||
minParams: 0,
|
minParams: 0,
|
||||||
|
@ -158,9 +158,10 @@ type Config struct {
|
|||||||
STS STSConfig
|
STS STSConfig
|
||||||
CheckIdent bool `yaml:"check-ident"`
|
CheckIdent bool `yaml:"check-ident"`
|
||||||
MOTD string
|
MOTD string
|
||||||
MOTDFormatting bool `yaml:"motd-formatting"`
|
MOTDFormatting bool `yaml:"motd-formatting"`
|
||||||
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
||||||
MaxSendQString string `yaml:"max-sendq"`
|
WebIRC []webircConfig `yaml:"webirc"`
|
||||||
|
MaxSendQString string `yaml:"max-sendq"`
|
||||||
MaxSendQBytes uint64
|
MaxSendQBytes uint64
|
||||||
ConnectionLimiter connection_limits.LimiterConfig `yaml:"connection-limits"`
|
ConnectionLimiter connection_limits.LimiterConfig `yaml:"connection-limits"`
|
||||||
ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
|
ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
|
||||||
@ -393,6 +394,22 @@ func LoadConfig(filename string) (config *Config, err error) {
|
|||||||
return nil, fmt.Errorf("Could not parse connection-throttle ban-duration: %s", err.Error())
|
return nil, fmt.Errorf("Could not parse connection-throttle ban-duration: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// process webirc blocks
|
||||||
|
var newWebIRC []webircConfig
|
||||||
|
for _, webirc := range config.Server.WebIRC {
|
||||||
|
// skip webirc blocks with no hosts (such as the example one)
|
||||||
|
if len(webirc.hosts) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = webirc.ProcessPassword()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not parse WebIRC config: %s", err.Error())
|
||||||
|
}
|
||||||
|
newWebIRC = append(newWebIRC, webirc)
|
||||||
|
}
|
||||||
|
config.Server.WebIRC = newWebIRC
|
||||||
|
// process limits
|
||||||
if config.Limits.LineLen.Tags < 512 || config.Limits.LineLen.Rest < 512 {
|
if config.Limits.LineLen.Tags < 512 || config.Limits.LineLen.Rest < 512 {
|
||||||
return nil, errors.New("Line lengths must be 512 or greater (check the linelen section under server->limits)")
|
return nil, errors.New("Line lengths must be 512 or greater (check the linelen section under server->limits)")
|
||||||
}
|
}
|
||||||
|
103
irc/gateways.go
Normal file
103
irc/gateways.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (c) 2012-2014 Jeremy Latt
|
||||||
|
// Copyright (c) 2014-2015 Edmund Huber
|
||||||
|
// Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
|
||||||
|
// released under the MIT license
|
||||||
|
|
||||||
|
package irc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/oragono/oragono/irc/passwd"
|
||||||
|
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
|
"github.com/oragono/oragono/irc/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type webircConfig struct {
|
||||||
|
passwordString string `yaml:"password"`
|
||||||
|
password []byte `yaml:"password-bytes"`
|
||||||
|
hosts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessPassword populates our password.
|
||||||
|
func (wc *webircConfig) ProcessPassword() error {
|
||||||
|
password, error := passwd.DecodePasswordHash(wc.passwordString)
|
||||||
|
wc.password = password
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
// WEBIRC password gateway hostname ip
|
||||||
|
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
// only allow unregistered clients to use this command
|
||||||
|
if client.registered {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
|
||||||
|
clientHostname := client.hostname
|
||||||
|
server.configurableStateMutex.RLock()
|
||||||
|
defer server.configurableStateMutex.RUnlock()
|
||||||
|
for _, info := range server.webirc {
|
||||||
|
for _, address := range info.hosts {
|
||||||
|
if clientHostname == address || clientAddress == address {
|
||||||
|
// confirm password
|
||||||
|
givenPassword := msg.Params[0]
|
||||||
|
if passwd.ComparePasswordString(info.password, givenPassword) == nil {
|
||||||
|
proxiedIP := msg.Params[3]
|
||||||
|
|
||||||
|
return client.ApplyProxiedIP(proxiedIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Quit("WEBIRC command is not usable from your address or incorrect password given")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROXY TCP4/6 SOURCEIP DESTIP SOURCEPORT DESTPORT
|
||||||
|
// http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
||||||
|
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
// only allow unregistered clients to use this command
|
||||||
|
if client.registered {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
|
||||||
|
clientHostname := client.hostname
|
||||||
|
server.configurableStateMutex.RLock()
|
||||||
|
defer server.configurableStateMutex.RUnlock()
|
||||||
|
for _, address := range server.proxyAllowedFrom {
|
||||||
|
if clientHostname == address || clientAddress == address {
|
||||||
|
proxiedIP := msg.Params[1]
|
||||||
|
|
||||||
|
return client.ApplyProxiedIP(proxiedIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.Quit("PROXY command is not usable from your address")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyProxiedIP applies the given IP to the client.
|
||||||
|
func (client *Client) ApplyProxiedIP(proxiedIP string) (exiting bool) {
|
||||||
|
// ensure IP is sane
|
||||||
|
parsedProxiedIP := net.ParseIP(proxiedIP)
|
||||||
|
if parsedProxiedIP == nil {
|
||||||
|
client.Quit(fmt.Sprintf("Proxied IP address is not valid: [%s]", proxiedIP))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
isBanned, banMsg := client.server.checkBans(parsedProxiedIP)
|
||||||
|
if isBanned {
|
||||||
|
client.Quit(banMsg)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// given IP is sane! override the client's current IP
|
||||||
|
client.proxiedIP = proxiedIP
|
||||||
|
client.rawHostname = utils.LookupHostname(proxiedIP)
|
||||||
|
client.hostname = client.rawHostname
|
||||||
|
return false
|
||||||
|
}
|
@ -460,6 +460,14 @@ Shows information about the given users. Takes up to 10 nicknames.`,
|
|||||||
text: `VERSION [server]
|
text: `VERSION [server]
|
||||||
|
|
||||||
Views the version of software and the RPL_ISUPPORT tokens for the given server.`,
|
Views the version of software and the RPL_ISUPPORT tokens for the given server.`,
|
||||||
|
},
|
||||||
|
"webirc": {
|
||||||
|
oper: true, // not really, but it's restricted anyways
|
||||||
|
text: `WEBIRC <password> <gateway> <hostname> <ip>
|
||||||
|
|
||||||
|
Used by web<->IRC gateways and bouncers, the WEBIRC command allows gateways to
|
||||||
|
pass-through the real IP addresses of clients:
|
||||||
|
ircv3.net/specs/extensions/webirc.html`,
|
||||||
},
|
},
|
||||||
"who": {
|
"who": {
|
||||||
text: `WHO <name> [o]
|
text: `WHO <name> [o]
|
||||||
|
@ -43,3 +43,8 @@ func DecodePasswordHash(encoded string) (decoded []byte, err error) {
|
|||||||
func ComparePassword(hash, password []byte) error {
|
func ComparePassword(hash, password []byte) error {
|
||||||
return bcrypt.CompareHashAndPassword(hash, password)
|
return bcrypt.CompareHashAndPassword(hash, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ComparePasswordString compares a given password string with the given hash.
|
||||||
|
func ComparePasswordString(hash []byte, password string) error {
|
||||||
|
return ComparePassword(hash, []byte(password))
|
||||||
|
}
|
||||||
|
@ -118,6 +118,7 @@ type Server struct {
|
|||||||
snomasks *SnoManager
|
snomasks *SnoManager
|
||||||
store *buntdb.DB
|
store *buntdb.DB
|
||||||
stsEnabled bool
|
stsEnabled bool
|
||||||
|
webirc []webircConfig
|
||||||
whoWas *WhoWasList
|
whoWas *WhoWasList
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1260,6 +1261,9 @@ func (server *Server) applyConfig(config *Config, initial bool) error {
|
|||||||
}
|
}
|
||||||
server.configurableStateMutex.Unlock()
|
server.configurableStateMutex.Unlock()
|
||||||
|
|
||||||
|
// apply new WebIRC command restrictions
|
||||||
|
server.webirc = config.Server.WebIRC
|
||||||
|
|
||||||
// apply new PROXY command restrictions
|
// apply new PROXY command restrictions
|
||||||
server.proxyAllowedFrom = config.Server.ProxyAllowedFrom
|
server.proxyAllowedFrom = config.Server.ProxyAllowedFrom
|
||||||
|
|
||||||
@ -2158,41 +2162,3 @@ func userhostHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROXY TCP4/6 SOURCEIP DESTIP SOURCEPORT DESTPORT
|
|
||||||
// http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
|
||||||
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|
||||||
// only allow unregistered clients to use this command
|
|
||||||
if client.registered {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
|
|
||||||
clientHostname := client.hostname
|
|
||||||
for _, address := range server.proxyAllowedFrom {
|
|
||||||
if clientHostname == address || clientAddress == address {
|
|
||||||
proxiedIP := msg.Params[1]
|
|
||||||
|
|
||||||
// ensure IP is sane
|
|
||||||
parsedProxiedIP := net.ParseIP(proxiedIP)
|
|
||||||
if parsedProxiedIP == nil {
|
|
||||||
client.Quit(fmt.Sprintf("Proxied IP address is not valid: [%s]", proxiedIP))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
isBanned, banMsg := server.checkBans(parsedProxiedIP)
|
|
||||||
if isBanned {
|
|
||||||
client.Quit(banMsg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// override the client's regular IP
|
|
||||||
client.proxiedIP = msg.Params[1]
|
|
||||||
client.rawHostname = utils.LookupHostname(msg.Params[1])
|
|
||||||
client.hostname = client.rawHostname
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
client.Quit("PROXY command is not usable from your address")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
13
oragono.yaml
13
oragono.yaml
@ -65,6 +65,19 @@ server:
|
|||||||
# - localhost
|
# - localhost
|
||||||
# - "127.0.0.1"
|
# - "127.0.0.1"
|
||||||
|
|
||||||
|
# controls the use of the WEBIRC command (by IRC<->web interfaces, bouncers and similar)
|
||||||
|
webirc:
|
||||||
|
# one webirc block -- should correspond to one set of gateways
|
||||||
|
-
|
||||||
|
# password the gateway uses to connect, made with oragono genpasswd
|
||||||
|
password: JDJhJDA0JG9rTTVERlNRa0hpOEZpNkhjZE95SU9Da1BseFdlcWtOTEQxNEFERVlqbEZNTkdhOVlYUkMu
|
||||||
|
|
||||||
|
# hosts that can use this webirc command
|
||||||
|
hosts:
|
||||||
|
# - localhost
|
||||||
|
# - "127.0.0.1"
|
||||||
|
# - "0::1"
|
||||||
|
|
||||||
# maximum length of clients' sendQ in bytes
|
# maximum length of clients' sendQ in bytes
|
||||||
# this should be big enough to hold /LIST and HELP replies
|
# this should be big enough to hold /LIST and HELP replies
|
||||||
max-sendq: 16k
|
max-sendq: 16k
|
||||||
|
Loading…
Reference in New Issue
Block a user