Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ gateway_name = "webircgateway"
# A secret string used for generating client JWT tokens. Do not share this!
secret = ""

# Webirc client certificate sent to servers when connecting with TLS
webirc_cert = ""
webirc_key = ""

# Send the server a quit message when the client is closed
# Comment out to disable
send_quit_on_client_close = "Client closed"
Expand Down
14 changes: 9 additions & 5 deletions pkg/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type KiwiProxyConnection struct {
DestTLS bool
State KiwiProxyState
Conn *net.Conn
WebircPemCert []byte
WebircPemKey []byte
}

func MakeKiwiProxyConnection() *KiwiProxyConnection {
Expand Down Expand Up @@ -63,11 +65,13 @@ func (c *KiwiProxyConnection) Dial(proxyServerAddr string) error {
c.State = KiwiProxyStateHandshaking

meta, _ := json.Marshal(map[string]interface{}{
"username": c.Username,
"interface": c.ProxyInterface,
"host": c.DestHost,
"port": c.DestPort,
"ssl": c.DestTLS,
"username": c.Username,
"interface": c.ProxyInterface,
"host": c.DestHost,
"port": c.DestPort,
"ssl": c.DestTLS,
"webirc_cert": c.WebircPemCert,
"webirc_key": c.WebircPemKey,
})

(*c.Conn).Write(append(meta, byte('\n')))
Expand Down
37 changes: 25 additions & 12 deletions pkg/proxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ var identdRpc *identd.RpcClient
var Server net.Listener

type HandshakeMeta struct {
Host string `json:"host"`
Port int `json:"port"`
TLS bool `json:"ssl"`
Username string `json:"username"`
Interface string `json:"interface"`
Host string `json:"host"`
Port int `json:"port"`
TLS bool `json:"ssl"`
Username string `json:"username"`
Interface string `json:"interface"`
WebircPemCert []byte `json:"webirc_cert"`
WebircPemKey []byte `json:"webirc_key"`
}

func MakeClient(conn net.Conn) *Client {
Expand All @@ -43,12 +45,13 @@ func MakeClient(conn net.Conn) *Client {
}

type Client struct {
Client net.Conn
Upstream net.Conn
UpstreamAddr *net.TCPAddr
Username string
BindAddr *net.TCPAddr
TLS bool
Client net.Conn
Upstream net.Conn
UpstreamAddr *net.TCPAddr
Username string
BindAddr *net.TCPAddr
TLS bool
WebircCertificate []tls.Certificate
}

func (c *Client) Run() {
Expand Down Expand Up @@ -88,6 +91,13 @@ func (c *Client) Handshake() error {
return unmarshalErr
}

if len(meta.WebircPemCert) > 0 && len(meta.WebircPemKey) > 0 {
webircCert, err := tls.X509KeyPair(meta.WebircPemCert, meta.WebircPemKey)
if err == nil {
c.WebircCertificate = []tls.Certificate{webircCert}
}
}

if meta.Host == "" || meta.Port == 0 || meta.Username == "" || meta.Interface == "" {
c.Client.Write([]byte(ResponseError))
return fmt.Errorf("missing args")
Expand Down Expand Up @@ -143,7 +153,10 @@ func (c *Client) ConnectUpstream() error {
}

if c.TLS {
tlsConfig := &tls.Config{InsecureSkipVerify: true}
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
Certificates: c.WebircCertificate,
}
tlsConn := tls.Client(conn, tlsConfig)
err := tlsConn.Handshake()
if err != nil {
Expand Down
27 changes: 26 additions & 1 deletion pkg/webircgateway/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,15 @@ func (c *Client) makeUpstreamConnection() (io.ReadWriteCloser, error) {
client := c
upstreamConfig := c.UpstreamConfig

// TODO remove me
upstreamConfig.Proxy = &ConfigProxy{
Type: "kiwi",
Hostname: "127.0.0.1",
Port: 7999,
TLS: false,
Username: client.IrcState.Username,
Interface: "0.0.0.0",
}
var connection io.ReadWriteCloser

if upstreamConfig.Proxy == nil {
Expand Down Expand Up @@ -343,7 +352,10 @@ func (c *Client) makeUpstreamConnection() (io.ReadWriteCloser, error) {
}

if upstreamConfig.TLS {
tlsConfig := &tls.Config{InsecureSkipVerify: true}
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
Certificates: upstreamConfig.WebircCertificate,
}
tlsConn := tls.Client(conn, tlsConfig)
err := tlsConn.Handshake()
if err != nil {
Expand All @@ -367,6 +379,8 @@ func (c *Client) makeUpstreamConnection() (io.ReadWriteCloser, error) {
conn.DestTLS = upstreamConfig.TLS
conn.Username = upstreamConfig.Proxy.Username
conn.ProxyInterface = upstreamConfig.Proxy.Interface
conn.WebircPemCert = upstreamConfig.WebircPemCert
conn.WebircPemKey = upstreamConfig.WebircPemKey

dialErr := conn.Dial(fmt.Sprintf(
"%s:%d",
Expand Down Expand Up @@ -401,6 +415,10 @@ func (c *Client) makeUpstreamConnection() (io.ReadWriteCloser, error) {

func (c *Client) writeWebircLines(upstream io.ReadWriteCloser) {
// Send any WEBIRC lines
if len(c.UpstreamConfig.WebircCertificate) > 0 && c.UpstreamConfig.WebircPassword == "" {
c.UpstreamConfig.WebircPassword = "*"
}

if c.UpstreamConfig.WebircPassword == "" {
c.Log(1, "No webirc to send")
return
Expand Down Expand Up @@ -696,7 +714,14 @@ func (c *Client) configureUpstream() ConfigUpstream {
upstreamConfig.Timeout = c.Gateway.Config.GatewayTimeout
upstreamConfig.Throttle = c.Gateway.Config.GatewayThrottle
upstreamConfig.WebircPassword = c.Gateway.findWebircPassword(c.DestHost)
upstreamConfig.WebircPemCert = c.Gateway.Config.WebircPemCert
upstreamConfig.WebircPemKey = c.Gateway.Config.WebircPemKey

if c.Gateway.Config.WebircCertificate.Certificate != nil {
upstreamConfig.WebircCertificate = []tls.Certificate{
*c.Gateway.Config.WebircCertificate,
}
}
return upstreamConfig
}

Expand Down
38 changes: 38 additions & 0 deletions pkg/webircgateway/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package webircgateway

import (
"crypto/tls"
"errors"
"io/ioutil"
"net"
"os"
"os/exec"
Expand All @@ -27,6 +29,9 @@ type ConfigUpstream struct {
ServerPassword string
GatewayName string
Proxy *ConfigProxy
WebircCertificate []tls.Certificate
WebircPemCert []byte
WebircPemKey []byte
}

// ConfigServer - A web server config
Expand Down Expand Up @@ -77,6 +82,9 @@ type Config struct {
ReCaptchaSecret string
ReCaptchaKey string
Secret string
WebircCertificate *tls.Certificate
WebircPemCert []byte
WebircPemKey []byte
Plugins []string
DnsblServers []string
// DnsblAction - "deny" = deny the connection. "verify" = require verification
Expand Down Expand Up @@ -148,6 +156,9 @@ func (c *Config) Load() error {
c.ReCaptchaKey = ""
c.RequiresVerification = false
c.Secret = ""
c.WebircCertificate = nil
c.WebircPemCert = make([]byte, 0)
c.WebircPemKey = make([]byte, 0)
c.SendQuitOnClientClose = ""
c.ClientRealname = ""
c.ClientUsername = ""
Expand All @@ -172,6 +183,33 @@ func (c *Config) Load() error {
}

c.Secret = section.Key("secret").MustString("")

// Load webirc client certificate
webircCert := section.Key("webirc_cert").MustString("")
webircKey := section.Key("webirc_key").MustString("")
if webircCert != "" && webircKey != "" {
certPath := c.ResolvePath(webircCert)
keyPath := c.ResolvePath(webircKey)

c.WebircPemCert, err = ioutil.ReadFile(certPath)
if err != nil {
c.gateway.Log(3, "Failed to load webirc certificate, "+err.Error())
continue
}

c.WebircPemKey, err = ioutil.ReadFile(keyPath)
if err != nil {
c.gateway.Log(3, "Failed to load webirc certificate, "+err.Error())
continue
}

webircCert, err := tls.X509KeyPair(c.WebircPemCert, c.WebircPemKey)
if err == nil {
c.WebircCertificate = &webircCert
} else {
c.gateway.Log(3, "Failed to load webirc certificate, "+err.Error())
}
}
c.SendQuitOnClientClose = section.Key("send_quit_on_client_close").MustString("Connection closed")
}

Expand Down