3
0
mirror of https://github.com/ergochat/ergo.git synced 2025-05-06 14:47:29 +02:00

WEBIRC: Allow protecting with fingerprint and parse tls flag

This commit is contained in:
Daniel Oaks 2017-10-16 08:47:49 +10:00
parent 07a16b2502
commit b0649cb5d3
4 changed files with 68 additions and 16 deletions

View File

@ -402,7 +402,7 @@ func LoadConfig(filename string) (config *Config, err error) {
continue continue
} }
err = webirc.ProcessPassword() err = webirc.Populate()
if err != nil { if err != nil {
return nil, fmt.Errorf("Could not parse WebIRC config: %s", err.Error()) return nil, fmt.Errorf("Could not parse WebIRC config: %s", err.Error())
} }

View File

@ -6,8 +6,10 @@
package irc package irc
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"strings"
"github.com/oragono/oragono/irc/passwd" "github.com/oragono/oragono/irc/passwd"
@ -18,23 +20,51 @@ import (
type webircConfig struct { type webircConfig struct {
PasswordString string `yaml:"password"` PasswordString string `yaml:"password"`
Password []byte `yaml:"password-bytes"` Password []byte `yaml:"password-bytes"`
Fingerprint string
Hosts []string Hosts []string
} }
// ProcessPassword populates our password. // Populate fills out our password or fingerprint.
func (wc *webircConfig) ProcessPassword() error { func (wc *webircConfig) Populate() (err error) {
password, error := passwd.DecodePasswordHash(wc.PasswordString) if wc.Fingerprint == "" && wc.PasswordString == "" {
wc.Password = password return errors.New("Fingerprint or password needs to be specified")
return error }
if wc.PasswordString != "" {
var password []byte
password, err = passwd.DecodePasswordHash(wc.PasswordString)
wc.Password = password
}
return err
} }
// WEBIRC password gateway hostname ip // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// only allow unregistered clients to use this command // only allow unregistered clients to use this command
if client.registered { if client.registered {
return false return false
} }
// process flags
var secure bool
if 4 < len(msg.Params) {
for _, x := range strings.Split(msg.Params[4], " ") {
// split into key=value
var key string
if strings.Contains(x, "=") {
y := strings.SplitN(x, "=", 2)
key, _ = y[0], y[1]
} else {
key = x
}
// only accept "tls" flag if the gateway's connection to us is secure as well
if strings.ToLower(key) == "tls" && client.flags[TLS] {
secure = true
}
}
}
clientAddress := utils.IPString(client.socket.conn.RemoteAddr()) clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
clientHostname := client.hostname clientHostname := client.hostname
server.configurableStateMutex.RLock() server.configurableStateMutex.RLock()
@ -42,13 +72,17 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
for _, info := range server.webirc { for _, info := range server.webirc {
for _, address := range info.Hosts { for _, address := range info.Hosts {
if clientHostname == address || clientAddress == address { if clientHostname == address || clientAddress == address {
// confirm password // confirm password and/or fingerprint
givenPassword := msg.Params[0] givenPassword := msg.Params[0]
if passwd.ComparePasswordString(info.Password, givenPassword) == nil { if 0 < len(info.Password) && passwd.ComparePasswordString(info.Password, givenPassword) != nil {
proxiedIP := msg.Params[3] continue
return client.ApplyProxiedIP(proxiedIP)
} }
if 0 < len(info.Fingerprint) && client.certfp != info.Fingerprint {
continue
}
proxiedIP := msg.Params[3]
return client.ApplyProxiedIP(proxiedIP, secure)
} }
} }
} }
@ -73,7 +107,8 @@ func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
if clientHostname == address || clientAddress == address { if clientHostname == address || clientAddress == address {
proxiedIP := msg.Params[1] proxiedIP := msg.Params[1]
return client.ApplyProxiedIP(proxiedIP) // assume PROXY connections are always secure
return client.ApplyProxiedIP(proxiedIP, true)
} }
} }
client.Quit("PROXY command is not usable from your address") client.Quit("PROXY command is not usable from your address")
@ -81,7 +116,7 @@ func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
} }
// ApplyProxiedIP applies the given IP to the client. // ApplyProxiedIP applies the given IP to the client.
func (client *Client) ApplyProxiedIP(proxiedIP string) (exiting bool) { func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (exiting bool) {
// ensure IP is sane // ensure IP is sane
parsedProxiedIP := net.ParseIP(proxiedIP) parsedProxiedIP := net.ParseIP(proxiedIP)
if parsedProxiedIP == nil { if parsedProxiedIP == nil {
@ -99,5 +134,14 @@ func (client *Client) ApplyProxiedIP(proxiedIP string) (exiting bool) {
client.proxiedIP = proxiedIP client.proxiedIP = proxiedIP
client.rawHostname = utils.LookupHostname(proxiedIP) client.rawHostname = utils.LookupHostname(proxiedIP)
client.hostname = client.rawHostname client.hostname = client.rawHostname
// set tls info
client.certfp = ""
if tls {
client.flags[TLS] = true
} else {
delete(client.flags, TLS)
}
return false return false
} }

View File

@ -463,11 +463,16 @@ Views the version of software and the RPL_ISUPPORT tokens for the given server.`
}, },
"webirc": { "webirc": {
oper: true, // not really, but it's restricted anyways oper: true, // not really, but it's restricted anyways
text: `WEBIRC <password> <gateway> <hostname> <ip> text: `WEBIRC <password> <gateway> <hostname> <ip> [:<flags>]
Used by web<->IRC gateways and bouncers, the WEBIRC command allows gateways to Used by web<->IRC gateways and bouncers, the WEBIRC command allows gateways to
pass-through the real IP addresses of clients: pass-through the real IP addresses of clients:
ircv3.net/specs/extensions/webirc.html`, ircv3.net/specs/extensions/webirc.html
<flags> is a list of space-separated strings indicating various details about
the connection from the client to the gateway, such as:
- tls: this flag indicates that the client->gateway connection is secure`,
}, },
"who": { "who": {
text: `WHO <name> [o] text: `WHO <name> [o]

View File

@ -69,6 +69,9 @@ server:
webirc: webirc:
# one webirc block -- should correspond to one set of gateways # one webirc block -- should correspond to one set of gateways
- -
# tls fingerprint the gateway must connect with to use this webirc block
fingerprint: 938dd33f4b76dcaf7ce5eb25c852369cb4b8fb47ba22fc235aa29c6623a5f182
# password the gateway uses to connect, made with oragono genpasswd # password the gateway uses to connect, made with oragono genpasswd
password: JDJhJDA0JG9rTTVERlNRa0hpOEZpNkhjZE95SU9Da1BseFdlcWtOTEQxNEFERVlqbEZNTkdhOVlYUkMu password: JDJhJDA0JG9rTTVERlNRa0hpOEZpNkhjZE95SU9Da1BseFdlcWtOTEQxNEFERVlqbEZNTkdhOVlYUkMu