Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
03006d070a | ||
![]() |
d3c805f6f4 | ||
![]() |
ebfb181a5b | ||
![]() |
bb15e1db9e | ||
![]() |
984f067966 | ||
![]() |
1f953d37fd | ||
![]() |
942364517d | ||
![]() |
31750200ea | ||
![]() |
4b67a1e91d |
2
go.mod
2
go.mod
@@ -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
6
go.sum
@@ -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=
|
||||
|
@@ -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")
|
||||
}
|
||||
|
||||
|
123
irc/server.go
123
irc/server.go
@@ -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
|
||||
//
|
||||
|
18
ircd.yml
18
ircd.yml
@@ -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)
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user