9 Commits

6 changed files with 165 additions and 2 deletions

2
go.mod
View File

@@ -4,6 +4,8 @@ go 1.14
require (
github.com/DanielOaks/girc-go v0.0.0-20180430075055-8d136c4f9287
github.com/cretz/bine v0.1.0
github.com/eyedeekay/sam3 v0.32.31
github.com/google/uuid v1.1.0 // indirect
github.com/goshuirc/e-nfa v0.0.0-20160917075329-7071788e3940 // indirect
github.com/imdario/mergo v0.3.11

6
go.sum
View File

@@ -6,9 +6,13 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLM
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/cretz/bine v0.1.0 h1:1/fvhLE+fk0bPzjdO5Ci+0ComYxEMuB1JhM4X5skT3g=
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eyedeekay/sam3 v0.32.31 h1:0fdDAupEQZSETHcyVQAsnFgpYArGJzU+lC2qN6f0GDk=
github.com/eyedeekay/sam3 v0.32.31/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -74,6 +78,7 @@ github.com/thoj/go-ircevent v0.0.0-20180816043103-14f3614f28c3/go.mod h1:QYOctLs
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -88,6 +93,7 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=

View File

@@ -19,6 +19,18 @@ type TLSConfig struct {
Cert string
}
type I2PConfig struct {
I2Pkeys string
SAMaddr string
Base32 string
}
type TorConfig struct {
Torkeys string
ControlPort int
Onion string
}
func (conf *PassConfig) PasswordBytes() []byte {
bytes, err := DecodePassword(conf.Password)
if err != nil {
@@ -39,6 +51,8 @@ type Config struct {
PassConfig `yaml:",inline"`
Listen []string
TLSListen map[string]*TLSConfig
I2PListen map[string]*I2PConfig
TorListen map[string]*TorConfig
Log string
MOTD string
Name string
@@ -111,7 +125,7 @@ func LoadConfig(filename string) (config *Config, err error) {
return nil, errors.New("Server name must match the format of a hostname")
}
if len(config.Server.Listen)+len(config.Server.TLSListen) == 0 {
if len(config.Server.Listen)+len(config.Server.TLSListen)+len(config.Server.I2PListen) == 0 {
return nil, errors.New("Server listening addresses missing")
}

View File

@@ -3,10 +3,12 @@ package irc
import (
"bufio"
"bytes"
"context"
"crypto/rand"
"crypto/tls"
"encoding/base64"
"fmt"
"io/ioutil"
"net"
"os"
"os/signal"
@@ -14,6 +16,10 @@ import (
"syscall"
"time"
"github.com/cretz/bine/tor"
"github.com/cretz/bine/torutil/ed25519"
"github.com/eyedeekay/sam3"
"github.com/eyedeekay/sam3/i2pkeys"
log "github.com/sirupsen/logrus"
)
@@ -95,6 +101,22 @@ func NewServer(config *Config) *Server {
server.listentls(addr, tlsconfig)
}
for addr, i2pconfig := range config.Server.I2PListen {
server.listeni2p(addr, i2pconfig)
err := ioutil.WriteFile(i2pconfig.I2Pkeys+".i2p.public.txt", []byte(i2pconfig.Base32), 0644)
if err != nil {
log.Fatalf("error storing I2P base32 address in adjacent text file")
}
}
for addr, torconfig := range config.Server.TorListen {
server.listentor(addr, torconfig)
err := ioutil.WriteFile(torconfig.Torkeys+".tor.public.txt", []byte(torconfig.Onion), 0644)
if err != nil {
log.Fatalf("error storing Tor onion address in adjacent text file")
}
}
signal.Notify(server.signals, SERVER_SIGNALS...)
// server uptime counter
@@ -284,6 +306,107 @@ func (s *Server) listentls(addr string, tlsconfig *TLSConfig) {
go s.acceptor(listener)
}
//
// listen i2p goroutine
//
func (s *Server) listeni2p(addr string, i2pconfig *I2PConfig) {
sam, err := sam3.NewSAM(i2pconfig.SAMaddr)
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", addr, err)
}
var keys *i2pkeys.I2PKeys
if _, err := os.Stat(i2pconfig.I2Pkeys + ".i2p.private"); os.IsNotExist(err) {
f, err := os.Create(i2pconfig.I2Pkeys + ".i2p.private")
if err != nil {
log.Fatalf("unable to open I2P keyfile for writing: %s", err)
}
defer f.Close()
tkeys, err := sam.NewKeys()
if err != nil {
log.Fatalf("unable to generate I2P Keys, %s", err)
}
keys = &tkeys
err = i2pkeys.StoreKeysIncompat(*keys, f)
if err != nil {
log.Fatalf("unable to save newly generated I2P Keys, %s", err)
}
i2pconfig.Base32 = keys.Addr().Base32()
} else {
tkeys, err := i2pkeys.LoadKeys(i2pconfig.I2Pkeys + ".i2p.private")
if err != nil {
log.Fatalf("unable to load I2P Keys: %e", err)
}
keys = &tkeys
}
// If the keys and the base32 are different, keys win.
i2pconfig.Base32 = keys.Addr().Base32()
stream, err := sam.NewStreamSession(addr, *keys, sam3.Options_Medium)
if err != nil {
log.Fatalf("error creating I2P streaming connection %s: %s, %s.", addr, err, *keys)
}
listener, err := stream.Listen()
if err != nil {
log.Fatalf("error binding to %s: %s", keys.Addr().Base32(), err)
}
log.Infof("Listening on I2P address, %s", keys.Addr().Base32(), err)
go s.acceptor(listener)
}
//
// listen tor goroutine
//
func (s *Server) listentor(addr string, torconfig *TorConfig) {
log.Infof("Starting and registering onion service, please wait a couple of minutes...")
t, err := tor.Start(nil, &tor.StartConf{ControlPort: torconfig.ControlPort})
if err != nil {
log.Fatalf("Unable to start Tor: %v", err)
}
var keys *ed25519.KeyPair
if _, err := os.Stat(torconfig.Torkeys + ".tor.private"); os.IsNotExist(err) {
tkeys, err := ed25519.GenerateKey(nil)
if err != nil {
log.Fatalf("Unable to generate onion service key, %s", err)
}
keys = &tkeys
f, err := os.Create(torconfig.Torkeys + ".tor.private")
if err != nil {
log.Fatalf("Unable to create Tor keys file for writing, %s", err)
}
defer f.Close()
_, err = f.Write(tkeys.PrivateKey())
if err != nil {
log.Fatalf("Unable to write Tor keys to disk, %s", err)
}
} else if err == nil {
tkeys, err := ioutil.ReadFile(torconfig.Torkeys + ".tor.private")
if err != nil {
log.Fatalf("Unable to read Tor keys from disk")
}
k := ed25519.FromCryptoPrivateKey(tkeys)
keys = &k
} else {
log.Fatalf("Unable to set up Tor keys, %s", err)
}
listenCtx := context.Background()
// Create a v3 onion service to listen on any port but show as 6667
listener, err := t.Listen(
listenCtx,
&tor.ListenConf{
Version3: true,
RemotePorts: []int{6667},
Key: *keys,
},
)
if err != nil {
log.Fatalf("Unable to create onion service: %v", err)
}
torconfig.Onion = listener.ID + ".onion"
log.Infof("Listening on Onion address, %s", listener.ID, torconfig.Onion, err)
go s.acceptor(listener)
}
//
// server functionality
//

View File

@@ -18,6 +18,24 @@ server:
":6697":
key: key.pem
cert: cert.pem
# Addresses to listen on for Invisible Internet
# note that if you choose this option, your ircd.yml will be
# rewritten to include the I2P address of your IRC server.
# You will lose any comments in your ircd.yml file
# i2plisten:
# "invisibleirc":
# i2pkeys: iirc
# samaddr: "127.0.0.1:7656"
# Addresses to listen on for Tor Onion Services.
# note that if you choose this option, your ircd.yml will be
# rewritten to include the Onion address of your IRC server.
# You will lose any comments in your ircd.yml
# torlisten:
# hiddenirc:
# torkeys: tirc
# controlport: 0
# password to login to the server
# generated using "mkpasswd" (from https://github.com/prologic/mkpasswd)

View File

@@ -38,7 +38,7 @@ func setupServer() *eris.Server {
// SASL
config.Account = map[string]*eris.PassConfig{
"admin": &eris.PassConfig{"JDJhJDA0JGtUU1JVc1JOUy9DbEh1WEdvYVlMdGVnclp6YnA3NDBOZGY1WUZhdTZtRzVmb1VKdXQ5ckZD"},
"admin": {"JDJhJDA0JGtUU1JVc1JOUy9DbEh1WEdvYVlMdGVnclp6YnA3NDBOZGY1WUZhdTZtRzVmb1VKdXQ5ckZD"},
}
server := eris.NewServer(config)