2017-10-15 08:18:14 +02:00
|
|
|
// 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 (
|
2017-10-16 00:47:49 +02:00
|
|
|
"errors"
|
2017-10-15 08:18:14 +02:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2017-10-16 00:47:49 +02:00
|
|
|
"strings"
|
2017-10-15 08:18:14 +02:00
|
|
|
|
|
|
|
"github.com/oragono/oragono/irc/passwd"
|
|
|
|
|
|
|
|
"github.com/goshuirc/irc-go/ircmsg"
|
|
|
|
"github.com/oragono/oragono/irc/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
type webircConfig struct {
|
2017-10-15 10:15:18 +02:00
|
|
|
PasswordString string `yaml:"password"`
|
|
|
|
Password []byte `yaml:"password-bytes"`
|
2017-10-16 00:47:49 +02:00
|
|
|
Fingerprint string
|
2017-10-15 10:15:18 +02:00
|
|
|
Hosts []string
|
2017-10-15 08:18:14 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 00:47:49 +02:00
|
|
|
// Populate fills out our password or fingerprint.
|
|
|
|
func (wc *webircConfig) Populate() (err error) {
|
|
|
|
if wc.Fingerprint == "" && wc.PasswordString == "" {
|
|
|
|
return errors.New("Fingerprint or password needs to be specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
if wc.PasswordString != "" {
|
|
|
|
var password []byte
|
|
|
|
password, err = passwd.DecodePasswordHash(wc.PasswordString)
|
|
|
|
wc.Password = password
|
|
|
|
}
|
|
|
|
return err
|
2017-10-15 08:18:14 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 00:47:49 +02:00
|
|
|
// WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
|
2017-10-15 08:18:14 +02:00
|
|
|
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|
|
|
// only allow unregistered clients to use this command
|
|
|
|
if client.registered {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-10-16 00:47:49 +02:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-15 08:18:14 +02:00
|
|
|
clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
|
|
|
|
clientHostname := client.hostname
|
2017-10-16 00:01:59 +02:00
|
|
|
for _, info := range server.WebIRCConfig() {
|
2017-10-15 10:15:18 +02:00
|
|
|
for _, address := range info.Hosts {
|
2017-10-15 08:18:14 +02:00
|
|
|
if clientHostname == address || clientAddress == address {
|
2017-10-16 00:47:49 +02:00
|
|
|
// confirm password and/or fingerprint
|
2017-10-15 08:18:14 +02:00
|
|
|
givenPassword := msg.Params[0]
|
2017-10-16 00:47:49 +02:00
|
|
|
if 0 < len(info.Password) && passwd.ComparePasswordString(info.Password, givenPassword) != nil {
|
|
|
|
continue
|
2017-10-15 08:18:14 +02:00
|
|
|
}
|
2017-10-16 00:47:49 +02:00
|
|
|
if 0 < len(info.Fingerprint) && client.certfp != info.Fingerprint {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
proxiedIP := msg.Params[3]
|
|
|
|
return client.ApplyProxiedIP(proxiedIP, secure)
|
2017-10-15 08:18:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-22 12:26:01 +01:00
|
|
|
client.Quit(client.t("WEBIRC command is not usable from your address or incorrect password given"))
|
2017-10-15 08:18:14 +02:00
|
|
|
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
|
2017-10-16 00:01:59 +02:00
|
|
|
for _, address := range server.ProxyAllowedFrom() {
|
2017-10-15 08:18:14 +02:00
|
|
|
if clientHostname == address || clientAddress == address {
|
|
|
|
proxiedIP := msg.Params[1]
|
|
|
|
|
2017-10-16 00:47:49 +02:00
|
|
|
// assume PROXY connections are always secure
|
|
|
|
return client.ApplyProxiedIP(proxiedIP, true)
|
2017-10-15 08:18:14 +02:00
|
|
|
}
|
|
|
|
}
|
2018-01-22 12:26:01 +01:00
|
|
|
client.Quit(client.t("PROXY command is not usable from your address"))
|
2017-10-15 08:18:14 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// ApplyProxiedIP applies the given IP to the client.
|
2017-10-16 00:47:49 +02:00
|
|
|
func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (exiting bool) {
|
2017-10-15 08:18:14 +02:00
|
|
|
// ensure IP is sane
|
|
|
|
parsedProxiedIP := net.ParseIP(proxiedIP)
|
|
|
|
if parsedProxiedIP == nil {
|
2018-01-22 12:26:01 +01:00
|
|
|
client.Quit(fmt.Sprintf(client.t("Proxied IP address is not valid: [%s]"), proxiedIP))
|
2017-10-15 08:18:14 +02:00
|
|
|
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
|
2017-10-16 00:47:49 +02:00
|
|
|
|
|
|
|
// set tls info
|
|
|
|
client.certfp = ""
|
|
|
|
if tls {
|
|
|
|
client.flags[TLS] = true
|
|
|
|
} else {
|
|
|
|
delete(client.flags, TLS)
|
|
|
|
}
|
|
|
|
|
2017-10-15 08:18:14 +02:00
|
|
|
return false
|
|
|
|
}
|